Tutorial by Examples

Declaration: class MyGenericClass<T1, T2, T3, ...> { // Do something with the type parameters. } Initialisation: var x = new MyGenericClass<int, char, bool>(); Usage (as the type of a parameter): void AnotherMethod(MyGenericClass<float, byte, char> arg) { ... } ...
Declaration: void MyGenericMethod<T1, T2, T3>(T1 a, T2 b, T3 c) { // Do something with the type parameters. } Invocation: There is no need to supply type arguements to a genric method, because the compiler can implicitly infer the type. int x =10; int y =20; string z = "tes...
Declaration: interface IMyGenericInterface<T1, T2, T3, ...> { ... } Usage (in inheritance): class ClassA<T1, T2, T3> : IMyGenericInterface<T1, T2, T3> { ... } class ClassB<T1, T2> : IMyGenericInterface<T1, T2, int> { ... } class ClassC<T1> : IMyGenericI...
When passing formal arguments to a generic method, relevant generic type arguments can usually be inferred implicitly. If all generic type can be inferred, then specifying them in the syntax is optional. Consider the following generic method. It has one formal parameter and one generic type paramet...
Type constraints are able to force a type parameter to implement a certain interface or class. interface IType; interface IAnotherType; // T must be a subtype of IType interface IGeneric<T> where T : IType { } // T must be a subtype of IType class Generic<T> where T...
It is possible to specify whether or not the type argument should be a reference type or a value type by using the respective constraints class or struct. If these constraints are used, they must be defined before all other constraints (for example a parent type or new()) can be listed. // TRef mus...
By using the new() constraint, it is possible to enforce type parameters to define an empty (default) constructor. class Foo { public Foo () { } } class Bar { public Bar (string s) { ... } } class Factory<T> where T : new() { public T Create() { re...
Developers can be caught out by the fact that type inference doesn't work for constructors: class Tuple<T1,T2> { public Tuple(T1 value1, T2 value2) { } } var x = new Tuple(2, "two"); // This WON'T work... var y = new Tuple<int, string>(2, "t...
The typeof operator works on type parameters. class NameGetter<T> { public string GetTypeName() { return typeof(T).Name; } }
There are different cases where you must Explicitly specify the type parameters for a generic method. In both of the below cases, the compiler is not able to infer all of the type parameters from the specified method parameters. One case is when there are no parameters: public void SomeMethod<T...
This is an example of how to use the generic type TFood inside Eat method on the class Animal public interface IFood { void EatenBy(Animal animal); } public class Grass: IFood { public void EatenBy(Animal animal) { Console.WriteLine("Grass was eaten by: {0}",...
When is an IEnumerable<T> a subtype of a different IEnumerable<T1>? When T is a subtype of T1. IEnumerable is covariant in its T parameter, which means that IEnumerable's subtype relationship goes in the same direction as T's. class Animal { /* ... */ } class Dog : Animal { /* ... */ }...
When is an IComparer<T> a subtype of a different IComparer<T1>? When T1 is a subtype of T. IComparer is contravariant in its T parameter, which means that IComparer's subtype relationship goes in the opposite direction as T's. class Animal { /* ... */ } class Dog : Animal { /* ... */ }...
IList<T> is never a subtype of a different IList<T1>. IList is invariant in its type parameter. class Animal { /* ... */ } class Dog : Animal { /* ... */ } IList<Dog> dogs = new List<Dog>(); IList<Animal> animals = dogs; // type error There is no subtype relat...
Interfaces may have variant type parameters. interface IEnumerable<out T> { // ... } interface IComparer<in T> { // ... } but classes and structures may not class BadClass<in T1, out T2> // not allowed { } struct BadStruct<in T1, out T2> // not allo...
Delegates may have variant type parameters. delegate void Action<in T>(T t); // T is an input delegate T Func<out T>(); // T is an output delegate T2 Func<in T1, out T2>(); // T1 is an input, T2 is an output This follows from the Liskov Substitution Principle, w...
If a covariant type appears as an output, the containing type is covariant. Producing a producer of Ts is like producing Ts. interface IReturnCovariant<out T> { IEnumerable<T> GetTs(); } If a contravariant type appears as an output, the containing type is contravariant. Produc...
If logic of generic class or method requires checking equality of values having generic type, use EqualityComparer<TType>.Default property: public void Foo<TBar>(TBar arg1, TBar arg2) { var comparer = EqualityComparer<TBar>.Default; if (comparer.Equals(arg1,arg2) {...
/// <summary> /// Converts a data type to another data type. /// </summary> public static class Cast { /// <summary> /// Converts input to Type of default value or given as typeparam T /// </summary> /// <typepara...
/// <summary> /// Read configuration values from app.config and convert to specified types /// </summary> public static class ConfigurationReader { /// <summary> /// Get value from AppSettings by key, convert to Type of default value or typ...

Page 1 of 1