How Do You Establish Variance in Generic Types - C# (C Sharp)

What is Variance in Generic Types?

Variance is nothing but a discrepancy or conflict happening in the normal behavior. Assume that you have a generic type to which object is passed as type. To a generic type holding objects, can you assign strings? Logically speaking, you can do it since strings are also objects. But you cannot do such assignments. They will end in exception. This is because generic types are invariant by default. However the same scenario is acceptable in arraylist, because arraylist is covariant. But still you can make generic types behave as covariant by performing some workarounds.

This article discusses about few such variance occurrences in generic types and the workaround solution for accomplishing them. It doesn’t stop with that, C# version 4.0 permits generic types to be both co-variant and contra-variant. You will also learn about how to implement them.

How Do You Establish Variance in Generic Types of Earlier Versions of C#?

Assume that there is a generic list containing integers. There is one more generic list of type object. You want to add elements of integer list to this object list. How will you do it? Here is the likely way of coding for this scenario:

class sampleClass {
public static void Main() {
List<int> intList = new List<int>();
intList.Add(100);
intList.Add(200);
List<object> objList = intList;
}
}

Though the code highlighted above seems to be logical, it will not work. One other alterative solution for the code highlighted above will be:

List<object> objList = new List<object>();
objList.AddRange(intList);

This code will also end up in compilation error. This is because generic types are invariant in nature. You cannot assign or convert from one type to another even if an implicit conversion is possible between those types. Now what other work around solution can be provided to add values of intList to objList? Here is the solution:

class sampleClass {
public static void Add<L1, L2>(List<L1> List1, List<L2> List2) where L1 : L2 {
foreach (List1 element in L1) {
List2.Add(element);
}
}
public static void Main() {
sampleClass obj = new sampleClass();
List<int> intList = new List<int>();
intList.Add(100);
intList.Add(200);
List<object> objList = new List<object>();
obj.Add<int, object>(intList, objList);
List<string> stringList = new List<string>();
stringList.Add(“Hello”);
stringList.Add(“Hai”);
sampleClass obj1 = new sampleClass();
objList = new List<object>();
obj1.Add<string,object>(stringList, objList);
}
}

This solution will be compiled successfully without any issues. Here you have introduced a new method called Add which is used to add elements of list L1 to list L2. You might wonder what does L1:L2 mean. This is a constraint which enforces that the processing will be done only if L1 elements are compatible and can be convertible into L2 type elements. If you don’t mention the constraint, the following line of code becomes acceptable and it will end up in exception during execution:

obj1.Add<string,int>(stringList, intList);

This is not legal because string elements cannot be added to an integer list. To avoid such code, you enforce the constraint. Inside the Add method, you fetch each element of List1 and insert it into List2. This method is generic and you can pass any different type combinations to it. In Main() method, you have called the Add function twice. First time you add intList elements to objList and the second time you add stringList elements to objList. You deal with different types but use the same function. That is the specialty of using generics.

You go with this round about solutions because earlier versions of C# define generic types as invariant. But C# version 4.0 allows generic types to be co-variant as well as contra-variant. Do these terms sound new to you? In the examples discussed so far, you try to assign elements of a sub-type list to the base type. This is termed as co-variance. Contra-variance is the reverse process of co-variance. C# 4.0 supports both of them and hence you need not try with work arounds any more.

How Do You Establish Co-Variance in Generic Types of C# version 4.0?

You establish co-variance using out keyword on IEnumerable types. Consider the following example:

class sampleGeneric<out T>: IEnumerable<out T> { }
class sampleClass {
publis static void Main( ) {
sampleGeneric<int> intInstance = new sampleGeneric<int>();
sampleGeneric<object> objInstance= intInstance;
}
}

In this example, sampleGeneric of type int is assigned to sampleGeneric of type object.This is perfectly legal. But remember that co-variance can be established only with the out parameters and not with the in parameters. Consider the following example:

class sampleGeneric<in T1, out T2>:IEnumerable<in T1, out T2> { }
class sampleClass {
publis static void Main( ) {
sampleGeneric<int, int> intInstance = new sampleGeneric<int, int>();
sampleGeneric<object, int> objInstance1 = intInstance;
sampleGeneric<int, object> objInstance2 = intInstance;
}
}

In this example, you try to convert the in parameter type int of sampleGeneric<int, int> to sampleGeneric<object, int>. You cannot establish co-variance on in parameters. Hence it will not compile. However in the next line of code, you try to convert sampleGeneric<int, int> to sampleGeneric<int, object>. The second parameter of sampleGeneric is an out parameter. In case of out parameter, an int is compatible with object. That is permissible and therefore this line of code is legal.

How Do You Establish Contra-Variance in Generic Types of C# version 4.0?

One best example for contra-variance is the IComparer interface. The interface code will look like:

interface IComparer<in Type1> {
int Compare(Type1 argument1, Type1 argument2);
}

You can now use IComparer<object> to compare integers or strings.

| AppDomain class in .Net | Asynchronous programming in .Net | Better data transmission using Compressed Streams in .Net | Encoding and Decoding Data in .Net | Handling Unmanaged Code in .Net | How are Generics of C# Different from C++ Templates | How Do You Establish Variance in Generic Typesm: Reference Types | How Do You Identify Nullable Type in C#m: Reference Types | How Do You Perform Boxing On Nullable Types in C# |Overview of Code Access Security in .Net |


“Amazon and the Amazon logo are trademarks of Amazon.com, Inc. or its affiliates.”

| Privacy Policy for www.dotnet-guide.com | Disclosure | Contact |

Copyright - © 2004 - 2024 - All Rights Reserved.