AlexMelvin
4/29/2020 - 5:32 PM

C# Generics

Generics and Reflection

Terminology

A                             //non generic, bound
A<U, V>                       //generic,     bound,  open,   constructed
A<int, V>                     //generic,     bound,  open,   constructed
A<int, int>                   //generic,     bound,  closed, constructed
A<,> (used like typeof(A<,>)) //generic,     unbound

How to convert types at runtime:

var conveter = TypeDescriptor.GetConverter(typeof(TTsource);
var result = (TTarget)converter.ConvertTo(item, typeof(TTarget));

How to instantiate a generic type with 1 type parameter:

Type fooType = typeof(GenericFoo<>);
Type closedFooGenericType = fooType.MakeGenericType(typeof(Baz));

var foo = Activator.CreateInstance(closedFooGenericType) as GenericFoo<Baz>;

How to instantiate a generic type with 2 or more type parameters:

Type barType = typeof(GenericBar<,>); // typeof(GenericBar<,,>) --> for 3 type arguments
Type closedBarGenericType = barType.MakeGenericType(typeof(Bazz1), typeof(Bazz2));

var bar = Activator.CreateInstance(closedBarGenericType) as GenericBar<Bazz1, Bazz2>;

How to call a generic void Foo<T>() method:

typeof(SomeClass).GetMethod("Foo").MakeGenericMethod(typeof(Bar)).Invoke(someClassInstance, null);

Converting closed generic type int unbound generic type

typeof(IRepository<Bar>).GetGenericTypeDefinition() // ---> IRepository<>

In other words, the GetGenericTypeDefinition strips the type argument out from a generic type.

Generic Delegates

Built-in common delegates

  • Action<TInput>
  • Func<TInput,TOutput> or Func<TOutput>
  • Predecate<TInput>
  • Converter<TInput,TOutput> (public delegate TOutput Converter<in TInput,out TOutput>(TInput input);)
// Example
Converter<double, string> converter = d => d.ToString();
var strings = numbers.AsEnumerableOf<int, string)(converter);

Covariance and Contravariance

Person
   ^
   |
Employee
   ^
   |
Manager

<T> - Invariance

<out T> - Covariance (Child instead of Parent). return Type<Child> from Foo():Type<Parent>

<in T> - Contravariance (Parent instead of Child). Pass Type<Parent> as argument to: Foo(Type<Child>)


Interfaces hierarchy:


Interfaces' usage