Saturday, January 30, 2010

Lambda expressions in an argument list affect overload resolution in certain situations.
The following rule augments §7.4.2.3: Given a lambda expression L for which an inferred return type (§26.3.2) exists, an implicit conversion of L to a delegate type D1 is a better conversion than an implicit conversion of L to a delegate type D2 if D1 and D2 have identical parameter lists and the implicit conversion from L's inferred return type to D1's return type is a better conversion than the implicit conversion from L's inferred return type to D2's return type. If these conditions are not true, neither conversion is better.
The following example illustrates the effect of this rule.
class ItemList: List
{
public int Sum(Func selector) {
int sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}
public double Sum(Func selector) {
double sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}
}
The ItemList class has two Sum methods. Each takes a selector argument, which extracts the value to sum over from a list item. The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.
The Sum methods could for example be used to compute sums from a list of detail lines in an order.
class Detail
{
public int UnitCount;
public double UnitPrice;
...
}
void ComputeSums() {
ItemList orderDetails = GetOrderDetails(...);
int totalUnits = orderDetails.Sum(d => d.UnitCount);
double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
...
}
In the first invocation of orderDetails.Sum, both Sum methods are applicable because the lambda expression d => d.UnitCount is compatible with both Func and Func. However, overload resolution picks the first Sum method because the conversion to Func is better than the conversion to Func.
In the second invocation of orderDetails.Sum, only the second Sum method is applicable because the lambda expression d => d.UnitPrice * d.UnitCount produces a value of type double. Thus, overload resolution picks the second Sum method for that invocation.