}
public k key;
public t item;
public node<k,t> nextnode;
}
you can combine the constructor constraint with derivation constraint, provided the constructor
constraint appears last in the constraint list:
public class linkedlist<k,t> where k : icomparable<k>,new()
{...}
generics and casting
the c# compiler only lets you implicitly cast generic type parameters to object, or to constraint-specified
types, as shown in code block 5. such implicit casting is type safe because any incompatibility is
discovered at compile-time.
code block 5. implicit casting of generic type parameters
interface isomeinterface
{...}
class baseclass
{...}
class myclass<t> where t : baseclass,isomeinterface
{
void somemethod(t t)
{
isomeinterface obj1 = t;
baseclass obj2 = t;
object obj3 = t;
}
}
the compiler lets you explicitly cast generic type parameters to any other interface, but not to a class:
interface isomeinterface
{...}
class someclass
{...}
class myclass<t>
{
void somemethod(t t)
{
isomeinterface obj1 = (isomeinterface)t;//compiles
someclass obj2 = (someclass)t; //does not compile
}
}
however, you can force a cast from a generic type parameter to any other type using a temporary object
variable:
class someclass
{...}
class myclass<t>
{
void somemethod(t t)
{
object temp = t;
someclass obj = (someclass)temp;
}
}
needless to say, such explicit casting is dangerous because it may throw an exception at run time if the
concrete type used instead of the generic type parameter does not derive from the type to which you
explicitly cast. instead of risking a casting exception, a better approach is to use the is and as operators,
as shown in code block 6. the is operator returns true if the generic type parameter is of the queried
type, and as will perform a cast if the types are compatible, and will return null otherwise. you can use
is and as on both naked generic type parameters and on generic classes with specific parameters.
code block 6. using 'is' and 'as' operators on generic type parameters
public class myclass<t>
{
public void somemethod(t t)
{
if(t is int)
{...}
if(t is linkedlist<int,string>)
{...}
string str = t as string;
if(str != null)
{...}
linkedlist<int,string> list = t as linkedlist<int,string>;
if(list != null)
{...}
}
}
inheritance and generics
when deriving from a generic base class, you must provide a specific type instead of the base-class's
generic type parameter:
public class baseclass<t>
{...}
public class subclass : baseclass<int>
{...}
if the subclass is generic, instead of a concrete type, you can use the subclass generic type parameter as
the specified type for the generic base class:
public class subclass<t> : baseclass<t>
{...}
when using the subclass generic type parameters, you must repeat any constraints stipulated at the
base class level at the subclass level. for example, derivation constraint:
public class baseclass<t> where t : isomeinterface
{...}
public class subclass<t> : baseclass<t> where t : isomeinterface
{...}
or constructor constraint:
public class baseclass<t> where t : new()
{
public t somemethod()
{
return new t();
}
}
public class subclass<t> : baseclass<t> where t : new()
{...}
a base class can define virtual methods whose signatures use generic type parameters. when overriding
them, the subclass must provide the corresponding types in the method signatures:
public class baseclass<t>
{
public virtual t somemethod()
{...}
}
public class subclass: baseclass<int>
{
public override int somemethod()
{...}
}
if the subclass is generic it can also use its own generic type parameters for the override:
public class subclass<t>: baseclass<t>
{
public override t somemethod()
{...}
}
you can define generic interfaces, generic abstract classes, and even generic abstract methods. these
types behave like any other generic base type:
public interface isomeinterface<t>
{
t somemethod(t t);
}
public abstract class baseclass<t>
{
public abstract t somemethod(t t);
}
public class subclass<t> : baseclass<t>
{
public override t somemethod(t t)
{...)
}
there is an interesting use for generic abstract methods and generic interfaces. in c# 2.0, it is impossible
to use operators such as + or += on generic type parameters. for example, the following code does not
compile because c# 2.0 does not have operator constraints:
public class calculator<t>
{
public t add(t arg1,t arg2)
{