New features in C# 4.0

Posted by Andrea on 2009-07-07 17:26

Dynamic Lookup
Dynamic lookup allows you a unified approach to invoking things dynamically. With dynamic lookup, when you have an object in your hand you do not need to worry about whether it comes from COM, IronPython, the HTML DOM or reflection; you just apply operations to it and leave it to the runtime to figure out what exactly those operations mean for that particular object.

This affords you enormous flexibility, and can greatly simplify your code, but it does come with a significant drawback: Static typing is not maintained for these operations. A dynamic object is assumed at compile time to support any operation, and only at runtime will you get an error if it wasn’t so. Oftentimes this will be no loss, because the object wouldn’t have a static type anyway, in other cases it is a tradeoff between brevity and safety. In order to facilitate this tradeoff, it is a design goal of C# to allow you to opt in or opt out of dynamic behavior on every single call.

// Usage of dynamic types
dynamic d = 7; // implicit conversion
int i = d; // assignment conversion

// Usage of dynamic operations
dynamic y = GetDynamicObject(…);
y.M(7); // calling methods
y.f = y.P; // getting and settings fields and properties
y[“one”] = y[“two”]; // getting and setting thorugh indexers
int i = y + 3; // calling operators
string s = y(5,7); // invoking as a delegate

// Overload resolution
// Choose between the static overloads of M on Foo.
// The result is again of type dynamic.
Foo foo = new Foo();
dynamic d = new Bar();
var result = foo.M(d);

Named and Optional Arguments
Named and optional parameters are really two distinct features, but are often useful together. Optional parameters allow you to omit arguments to member invocations, whereas named arguments is a way to provide an argument using the name of the corresponding parameter instead of relying on its position in the parameter list.

Some APIs, most notably COM interfaces such as the Office automation APIs, are written specifically with named and optional parameters in mind. Up until now it has been very painful to call into these APIs from C#, with sometimes as many as thirty arguments having to be explicitly passed, most of which have reasonable default values and could be omitted.
Even in APIs for .NET however you sometimes find yourself compelled to write many overloads of a method with different combinations of parameters, in order to provide maximum usability to the callers. Optional parameters are a useful alternative for these situations.

// Optional parameters: a parameter is optional if it has a default value:
public void M(int x, int y = 5, int z = 7);
// Here y and z are optional parameters and can be omitted in calls:
M(1, 2, 3); // ordinary call of M
M(1, 2); // omitting z – equivalent to M(1, 2, 7)
M(1); // omitting both y and z – equivalent to M(1, 5, 7)

// Named and optional arguments: any argument can be passed by name.
// thus if you want to omit only y from a call of M you can write:
M(1, z: 3); // passing z by name
or
M(x: 1, z: 3); // passing both x and z by name
or even
M(z: 3, x: 1); // reversing the order of arguments

// Overload resolution: if two signatures are equally good,
// one that does not omit optional parameters is preferred.
M(string s, int i = 1);
M(object o);
M(int i, string s = “Hello”);
M(int i);
M(5); 

Features for COM interop
Dynamic lookup as well as named and optional parameters greatly improve the experience of interoperating with COM APIs such as the Office Automation APIs. In order to remove even more of the speed bumps, a couple of small COM-specific features are also added to C# 4.0.

Dynamic import
Basically you can easily access members directly off a returned object, or you can assign it to a strongly typed local variable without having to cast.

Compiling without PIAs
PIAs are large .NET assemblies generated from COM interfaces to facilitate strongly typed interoperability

Omitting ref
The compiler will allow you to pass arguments by value, and will automatically generate temporary variables to hold the passed-in values

Variance
An aspect of generics that often comes across as surprising is that the following is illegal:

IList strings = new List(); 
IList objects = strings;

The second assignment is disallowed because strings does not have the same element type as objects. There is a perfectly good reason for this. If it were allowed you could write:

objects[0] = 5; 
string s = strings[0];

Allowing an int to be inserted into a list of strings and subsequently extracted as a string. This would be a breach of type safety.
However, there are certain interfaces where the above cannot occur, notably where there is no way to insert an object into the collection. Such an interface is IEnumerable<T>. If instead you say:

IEnumerable<object> objects = strings;

There is no way we can put the wrong kind of thing into strings through objects, because objects doesn’t have a method that takes an element in. Variance is about allowing assignments such as this in cases where it is safe. The result is that a lot of situations that were previously surprising now just work.

Resources


Please note almost this entire post should be credited to Mads Torgesen, here you can find the original extended version.