return arg1 + arg2;//does not compile
}
//rest of the methods
}
nonetheless, you can compensate using abstract methods (or preferably interfaces) by defining generic
operations. since an abstract method cannot have any code in it, you can specify the generic operations
at the base class level, and provide a concrete type and implementation at the subclass level:
public abstract class basecalculator<t>
{
public abstract t add(t arg1,t arg2);
public abstract t subtract(t arg1,t arg2);
public abstract t divide(t arg1,t arg2);
public abstract t multiply(t arg1,t arg2);
}
public class mycalculator : basecalculator<int>
{
public override int add(int arg1, int arg2)
{
return arg1 + arg2;
}
//rest of the methods
}
a generic interface will yield a somewhat cleaner solution as well:
public interface icalculator<t>
{
t add(t arg1,t arg2);
//rest of the methods
}
public class mycalculator : icalculator<int>
{
public int add(int arg1, int arg2)
{
return arg1 + arg2;
}
//rest of the methods
}
generic methods
in c# 2.0, a method can define generic type parameters, specific to its execution scope:
public class myclass<t>
{
public void mymethod<x>(x x)
{...}
}
this is an important capability because it allows you to call the method with a different type every time,
which is very handy for utility classes.
you can define method-specific generic type parameters even if the containing class does not use
generics at all:
public class myclass
{
public void mymethod<t>(t t)
{...}
}
this ability is for methods only. properties or indexers can only use generic type parameters defined at
the scope of the class.
when calling a method that defines generic type parameters, you can provide the type to use at the call
site:
myclass obj = new myclass();
obj.mymethod<int>(3);
that said, when the method is invoked the c# compiler is smart enough to infer the correct type based
on the type of parameter passed in, and it allows omitting the type specification altogether:
myclass obj = new myclass();
obj.mymethod(3);
this ability is called generic type inference. note that the compiler cannot infer the type based on the
type of the returned value alone:
public class myclass
{
public t mymethod<t>()
{}
}
myclass obj = new myclass();
int number = obj.mymethod();//does not compile
when a method defines its own generic type parameters, it can also define constraints for these types:
public class myclass
{
public void somemethod<t>(t t) where t : icomparable<t>
{...}
}
however, you cannot provide method-level constraints for class-level generic type parameters. all
constraints for class-level generic type parameters must be defined at the class scope.
when overriding a virtual method that defines generic type parameters, the subclass method must
redefine the method-specific generic type parameter:
public class baseclass
{
public virtual void somemethod<t>(t t)
{...}
}
public class subclass : baseclass
{
public override void somemethod<t>(t t)
{...}
}
the subclass implementation must repeat all constraints that appeared at the base method level:
public class baseclass
{
public virtual void somemethod<t>(t t) where t : new()
{...}
}
public class subclass : baseclass
{
public override void somemethod<t>(t t) where t : new()
{...}
}
note that the method override cannot define new constraints that did not appear at the base method.
in addition, if the subclass method calls the base class implementation of the virtual method, it must
specify the type to use instead of the generic base method type parameter. you can either explicitly
specify it yourself or rely on type inference if it is available:
public class baseclass
{
public virtual void somemethod<t>(t t)
{...}
}
public class subclass : baseclass
{
public override void somemethod<t>(t t)
{
base.somemethod<t>(t);
base.somemethod(t);
}
}
generic static method
c# allows you to define static methods that use generic type parameters. however, when invoking such
a static method, you need to provide the concrete type for the containing class at the call site, such as in
this example:
public class myclass<t>
{
public static t somemethod(t t)
{...}
}
int number = myclass<int>.somemethod(3);
static methods can define method-specific generic type parameters and constraints, similar to instance
methods. when calling such methods, you need to provide the method-specific types at the call site,
either explicitly:
public class myclass<t>
{
public static t somemethod<x>(t t,x x)
{..}