C# 4.0 New Features

  1. Dynamic Typed Objects
  2. Optional and Named Parameters
  3. Improved COM Interoperability
  4. Co- and Contra-Variance

Dynamic lookup
Dynamic lookup 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.

object calc = GetCalculator();
Type type = calc.GetType();
object result = type.InvokeMember(
"Add",
BindingFlags.InvokeMethod,
null,
new object[] { 10, 20 });
int sum = Convert.ToInt32(result);

With the C# 4.0 we would simply write the following code:

dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);

In the above example we are declaring a variable, calc, whose static type is dynamic. We'll then be using dynamic method invocation to call the Add method and then dynamic conversion to convert the result of the dynamic invocation to a statically typed integer.


Named and optional parameters
Parameters in C# can now be specified as optional by providing a default value for them in a member declaration. When the member is invoked, optional arguments can be omitted. Furthermore, any argument can be passed by parameter name instead of position.

public StreamReader OpenTextFile(
string path,
Encoding encoding = null,
bool detectEncoding = false,
int bufferSize = 1024) { }


COM specific interop features
Dynamic lookup as well as named and optional parameters both help making programming against COM less painful than today. On top of that, however, we are adding a number of other small features that further improve the interop experience.

When you work with COM interop methods, you had to pass a reference to Missing.Value for unneeded parameters, like the following:

object filename = "test.docx";
object missing = System.Reflection.Missing.Value;

doc.SaveAs(ref filename,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);

Now, in C# 4.0 you can only write:

doc.SaveAs(filename);


Variance
It used to be that an IEnumerable wasn't an IEnumerable. Now it is – C# embraces type safe “co-and contravariance” and common BCL types are updated to take advantage of that.


Generics with C# 4.0 now support safe co-variance and contra-variance through the use of the in (contra-variant) and out (co-variant) contextual keywords. Let's take a look at how this changes the definition of the IEnumerable and IEnumerator interfaces.

public interface IEnumerable<out T>
{
IEnumerator GetEnumerator();
}

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

Given that an IEnumerable collection is read only, there is no ability specified within the interface to insert new elements, it is safe to treat a more derived element as something less derived. With the out contextual keyword we are contractually affirming that IEnumerable is safely co-variant. We can now write the following code without a compiler error:

IEnumerable<string> strings = GetStrings();
IEnumerable<object> objects = strings;

Using the in contextual keyword we can achieve safe contra-variance, that is treating something less derived as something more derived.

public interface IComparer<in T>
{
int Compare(T x, T y);
}

Given that IComparer is safely contra-variant we can now write the following code:

IComparer<object> objectComparer = GetComparer();
IComparer<string> stringComparer = objectComparer;

It is important to notice that co-variance in IEnumerable refers to the fact that its Current property can return a string instead of an object as output, while contra-variance in IComparer refers to the fact that its Compare method can accept an object instead of a string as input.

Next Recommended Reading How to use Tuple in c# 4.0