The new features in C# 4.0 are introduced considering interop & many of them already in VB .Net.
The new features fall into four groups:
- Dynamic lookup
- Named & optional parameters
- COM specific interop features
- Covariant and contravariant
Allows you to write method, operator and indexer calls, property and field accesses, and even object invocations which bypass the C# static type checking and instead gets resolved at runtime.
void Display(dynamic obj) { WriteLine(obj); // call is decided at run-time } Display(222); // i.e. WriteLine(int) Display("Hello"); // i.e. WriteLine(string)
Named & optional parameters
Parameters can be specified as optional by providing a default value in a member declaration. Optional arguments can be omitted & any argument can be passed by parameter name instead of position.
public void Foo(int x, int y = 3, int z = 9); // Here y and z are optional parameters and can be omitted in calls: Foo(1, 2, 3); // ordinary call of Foo Foo(1, 2); // omitting z – equivalent to Foo(1, 2, 7) Foo(1); // omitting both y and z – equivalent to Foo(1, 5, 7)
COM specific interop features
Dynamic import
Use of dynamic import - variants are represented using the type dynamic
((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello"; // before C#4.0 excel.Cells[1, 1].Value = "Hello"; // C#4.0 - dynamic import
Compiling without PIAs
Primary Interop Assemblies (PIAs) are large .NET assemblies generated from COM interfaces. At runtime these large assemblies can easily swell your program, and also cause versioning issues because they are distributed independently of your application.
The no-PIA feature allows you to continue to use PIAs at design time without having them around at runtime. Instead, the C# compiler will bake the small part of the PIA that a program actually uses directly into its assembly. At runtime the PIA does not have to be loaded.
Omitting ref
The ref keyword for callers of methods is now optional when calling into methods supplied by COM interfaces.
void AddStack(ref int x); // the invocation can now be written as AddStack(1); // no need for "ref" // old style int x = 5; AddStack(ref x);
Covariant and contravariant
Generic interfaces and delegates can have their type parameters marked as covariant or contravariant, using keywords out and in, respectively. These declarations are then respected for type conversions, both implicit and explicit, and both compile-time and run-time
Covariant Example
public interface IEnumerable<out T> : IEnumerable{ IEnumerator<T> GetEnumerator(); } public interface IEnumerator<out T> : IEnumerator{ bool MoveNext(); T Current { get; } }
The “out” in these declarations signifies that the T can only occur in output position in the interface
Using the declarations above you can write the following which was previously disallowed & requires some cumbersome wrapping to get the two sequences to have the same element type:
var result = strings.Union(objects); // succeeds with an IEnumerable
Contravariance Example
Type parameters can also have an “in” modifier, restricting them to occur only in input positions.
public interface IComparer<in T>{ public int Compare(T left, T right); }
Therefore, any class that implements IComparer<Base> for some class Base is also considered to be compatible with IComparer<Derived> for all classes and interfaces Derived that are extended from Base. It makes it possible to write code such as:
IComparer<object> objectComparer = GetComparer(); IComparer<string> stringComparer = objectComparer;