Why not generic derived type should specify type parameter for C # base base class
In Pro C # by Andrew Tolson, the author says that when a non-generic class extends a generic base class, the derived class must specify a type parameter.
// Assume you have created a custom
// generic list class.
public class MyList<T>
{
private List<T> listOfData = new List<T>();
}
// Non-generic classes must specify the type
// parameter when deriving from a
// generic base class.
public class MyStringList : MyList<string>
{}
What I don't understand, why is this necessary?
source to share
Well, not generic classes have no type parameters, but generic classes have one or more type parameters.
If you inherit a class from a generic class without specifying a type parameter, you still have a generic class, ie
public class MyList<T> : List<T> {} //MyList is still generic
but
public class MyList : List<T> {} //invalid declaration, what is T ?
So
public class MyStringList : List<string> {} //specified with string
or, more generally
public class MyArrayList : List<object> {} //specified with object
A more verbose explanation, mainly because I like to use the word arity . "
Classes in the CLR can have an arity of zero or more, which means they can specify zero or more type parameters. However, the CLR cannot create classes with nonzero arity, so in order to do anything useful, the arity of the class must be reduced to zero.
This means that while we can partially specify classes such as:
public class IntKeyDictionary<TValue> : Dictionary<int, TValue>
which reduce arity or even declare classes like
public class ListAndAHalf<TOne, TTwo> : List<TOne>
which increase arity, the story must end with a class with arity 0, for example List<string>
, Dictionary<int, double>
etc ...
source to share
Because it isn't used otherwise, because the CLR still doesn't know which type to use for T
.
List<T>
is public because it T
hasn't been replaced by an instance of the type yet. And you cannot instantiate public types. You can instantiate a type when it is closed , i.e. When all of its type parameters (including enclosing types and base types) have been replaced with instances of.
If you can declare class MyTList : MyList<T> { }
, then you will never be able to specify a type for T
because it MyTList
no longer includes that type parameter, so you can never instantiate MyTList
. This is not a very useful class.
source to share
Think about it the other way around. If you didn't provide a type parameter for your base type, which type should you use MyList<T>
? It will be undefined.
You can create a generic type that inherits from another generic type, and then you don't need to specify a supertype type parameter; your clients can do it.
source to share