Generic types (part 2, basics, advanced)
We have looked into generic classes in part 1 https://csharphardcoreprogramming.wordpress.com/2014/01/01/generic-types-part-1-basics-advanced/.
On the following day I used a generic method when explaining reflection https://csharphardcoreprogramming.wordpress.com/2014/01/02/reflection-basics-advanced/.
Let’s look at generic delegates more closely. They look neat and make code, as the name says, more generic.
delegate T Calc<T>(T a, T b); private static int Add(int a, int b) { return a + b; } private static double Multiply(double a, double b) { return a * b; } public static void Generics8() { Calc<double> lProduct = Multiply; Calc<int> lSum = Add; Console.WriteLine("Product:" + lProduct(5.0, 2.0)); Console.WriteLine("Sum:" + lSum(5, 2)); Console.ReadKey(); } //
We can also use constraints on delegates:
delegate T Calc<T>(T a, T b) where T : struct;
Generally we know the pattern now. And without much explanation a quick summary should cover all generic types:
// generic delegate delegate T myDelegate<T>(T t) where T : struct; // generic method void myMethod<T, U>(T a, T b, U c) {} // generic class class myClass<T> where T : System.IComparable<T>, IEnumerable<T> {} // generic interface interface IMyInterFace<out TResult, in TInput> { TResult DoSometing(TInput Args); }
Interfaces can make use of the in and out keywords.
The out keyword declares a generic type parameter covariant. The in keyword makes it contravariant.
Covariance and contravariance were introduced when I described delegates https://csharphardcoreprogramming.wordpress.com/2013/12/16/delegates-basics/ .
The out keyword can only be used as an input parameter if it is a contravariant generic delegate.
interface ICovariant<out T> { void DoSomething(Action<T> xCallback); }
The contravariant type (in) can only be used in method arguments and not as return types, it can also be used for generic constraints.
interface IContravariant<in T> { void DoSomething<U>() where U : T; }
There are certain rules about inheritance.
A covariant class cannot inherit from a contravariant class.
A contravariant class cannot inherit from a covariant class.
interface ICovariant<out T> { } interface IContravariant<in T> { } // all ok interface IInvariant1<T> : ICovariant<T> { } interface IInvariant2<T> : IContravariant<T> { } interface IInvariant3<T> : ICovariant<T>, IContravariant<T> { } interface ICovariant1<out T> : ICovariant<T> { } interface IContravariant1<in T> : IContravariant<T> { } // compiler error. //interface ICovariant2<out T> : IContravariant<T> { } //interface ICovariant3<out T> : ICovariant<T>, IContravariant<T> { } //interface IContravariant2<in T> : ICovariant<T> { } //interface IContravariant3<in T> : ICovariant<T>, IContravariant<T> { }
There is no generic type for Arrays. Backward compatibility did not allow an evolution here. Arrays are very basic, they can be used for high-performing applications. If Microsoft would make them more complex, we would somehow lose that benefit. My advice is to use generic collections/Lists instead. You can use T[], but this is rather a strongly typed array than a generic array.
public static void Generics9<T>() { T[] lArray = new T[10]; foreach (T lElement in lArray) { Console.WriteLine(lElement.ToString()); } } //
Posted on January 3, 2014, in Advanced, Basic, C#, Delegates, Generics and tagged C#, C-sharp, contravariance, covariance, generics, null, nullable, nullable type, reference type, value type, where T. Bookmark the permalink. Leave a comment.
Leave a comment
Comments 0