Browse DevX
Sign up for e-mail newsletters from DevX


COM Interop Gets Much Better in C# 4.0  : Page 2

Enhanced COM interop through C# 4.0's dynamic type system, support for named and optional parameters, and for variance makes working with Microsoft Office and other Primary Interop Assemblies much easier.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Support for Variance

With C# 4.0, you can specify in (input only) and out (return only) parameters on generic types. These parameters can then be passed as only input parameters or used only as return values for such types.

Support for variance in C# 4.0 can be twofold: covariance and contravariance. The terms invariance, covariance and contravariance deserve a bit of explanation. Bill Wagner writes: "A return value or parameter is invariant if you must use the exact match of the formal type name. A parameter is covariant if you can use a more derived type as a substitute for the formal parameter type. A return value is contravariant if you can assign the return type to a variable of a less derived type than the formal parameter."

Author's Note: I won't cover invariant parameters any further here—you're already more than familiar with those from earlier versions of C#.


Covariance is easier to understand with a simple example. Note that string is a specific type, whereas object is a generic type. So, string is covariant to object. Now, let’s see how .NET 4.0 supports covariance. The interface IEnumerable<T> is defined in .NET 4.0 as shown below:

public interface IEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator(); } public interface IEnumerator<out T> : IEnumerator { bool MoveNext(); T Current { get; } }

In earlier versions of C#, an IEnumerable<string> wasn’t an IEnumerable<object>. Notice the out parameter in the preceding IEnumerator<out T> definition, which indicates that generic T can occur only in the output position; otherwise, the compiler will report an error. The interface is covariant in T meaning that IEnumerable<P> is also IEnumerable<Q> provided P is derived from Q. So, a sequence of strings is also a sequence of objects. Hence, the following statement is perfectly valid:

IEnumerable<object> someObj = new List<string>();

The next example illustrates how you can make use of covariance in C# 4.0:

namespace Test { class Base { //Methods and Properties of the Base Class } class Derived : Base { //Methods and Properties of the Derived Class } class Program { delegate T TestFunction<out T>(); static void Main(string[] args) { TestFunction<Derived> derivedObj = () => new Derived(); TestFunction<Base> baseObj = derivedObj; } } }


Type parameters in generic interfaces in C# 4.0 can have an in modifier that allows them to occur in input positions only, for example:

public interface IComparer<in T> { public int Compare(T left, T right); }

So, a comparer that can compare objects can compare strings as well. This is called contravariance. A good example of contravariance is the Equals() method or the CompareTo() method. If you have a method that can compare two instances of a base class, you can use the same method to compare two instances of a derived class as well. You can easily store the result of any method calls in an instance of type object, because method return types in C# are contravariant.

Here's a contravariant counterpart of the preceding example:

namespace Test { class Base { } class Derived : Base { } class Program { delegate void TestDelegate<in T>(T a); static void Main(string[] args) { TestDelegate<Base> baseObj = (obj) => { System.Console.WriteLine(obj); }; TestDelegate<Derived> derivedObj = baseObj; } } }

Author's Note: Type variance works only on interfaces and delegate types. Variance can be applied only if there is a reference conversion between the type arguments. So, IEnumerable<int> is not an IEnumerable<object> because int is a value type and object is a reference type. In other words, conversion of an integer to an object type is a boxing conversion and not a reference conversion—and therefore is not an example of variance.

As you can see, C# 4.0's new features make working with Primary Interop Assemblies much more pleasant. The support for optional parameters means you don't have to explicitly pass "missing" values to functions in place of optional parameters you either don't have or don't need. The support for named parameters means you don't have to pass values in a specific order (as long as you use the names), and the support for variance eliminates many of the tedious and error-prone casts that were formerly required. All in all, these are welcome and useful changes.

Joydip Kanjilal has over 10 years of industry experience with C, C++, Java, C#, VB, VC++, ASP.Net, XML, Design Patterns, UML, etc. He currently works as a senior project leader in a reputable multinational company in Hyderabad, India, and has contributed articles on .NET and related technologies to www.aspalliance.com.
Thanks for your registration, follow us on our social networks to keep up-to-date