Monday, October 26, 2009

New features in C# 4.0 - 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 declared optional simply by providing a default value for it:
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

C# 4.0 does not permit you to omit arguments between commas as in M(1,,3). This could lead to highly unreadable comma-counting code. Instead 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

 All forms are equivalent, except that arguments are always evaluated in the order they appear, so in the last example the 3 is evaluated before the 1.

Optional and named arguments can be used not only with methods but also with indexers and constructors.

Overload resolution

Named and optional arguments affect overload resolution, but the changes are relatively simple:
A signature is applicable if all its parameters are either optional or have exactly one corresponding argument (by name or position) in the call which is convertible to the parameter type.
Betterness rules on conversions are only applied for arguments that are explicitly given – omitted optional arguments are ignored for betterness purposes.

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);

Given these overloads, we can see the working of the rules above.M(string,int) is not applicable because 5 doesn’t convert to string.
M(int,string) is applicable because its second parameter is optional, and so, obviously are M(object) and M(int).

M(int,string) and M(int) are both better than M(object) because the conversion from 5 to int is better than the conversion from 5 to object.

Finally M(int) is better than M(int,string) because no optional arguments are omitted.
Thus the method that gets called is M(int).

No comments:

Post a Comment