人生中的第一篇博客,好吧我承认其实我很懒(开博一周了啥都没写)。本文灵感来源于鹤冲天一个有歧义的lambda表达式,这里我把问题简化一下:

static void Main(string[] args)
{
     Test(i => i = 1);
}

static void Test(Action<int> action)
{
     action(1);
}

static void Test(Func<int, object> func)
{
     func(1);
}

在实际执行中,接收参数Func<int,object>的Test方法将被执行,如果将它注释掉,则执行接收Action<int>的Test方法。接下来我将一步一步说明原因。

首先要了解的是:C#中的赋值语句是有值的,它的值就是赋值操作完成后,赋值号(=)左边表达式的值(这就是为什么我们可以写y=x=1)这样的语句来初始化一系列的变量。第二点要说的就是在C#中,某些labmda表达式可以简写。如(T1,T2) => { return something; }可以简写为(T1,T2) => something;以及(T1,T2) => { dosomething; } 可以简写为 (T1,T2) => dosomething。那么我们再来看上文的lambda表达式,它可能是两个表达式的简写:(1) i => { i = 1; } 这个时候很明显它是一个Action<int>(注1),如果你不采用简写的话那么上面的例子毫无疑问会执行第一个Test方法(因为不满足第二个的参数类型)。 (2) i => { return i = 1; } 这个时候明显它是一个Func<int,int>,同时也是一个Func<int, object>。在这种不明确的情况下,C#是如何选择执行方法的呢?CLS给了我们很好的答案:

7.4.3.2 Better function member

Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function member than MQ if

  • for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and
  • for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.

当多个方法签名都符合调用的时候,编译器有一套选择的准则来选择“更好的方法”,从上面的CLS引用可以看出,编译器会将具有“更好的参数”的函数作为“更好的方法”。那么怎么才是一个更好的参数呢?继续查:

7.4.3.3 Better conversion from expression

Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, the better conversion of the two conversions is determined as follows:

  • If T1 and T2 are the same type, neither conversion is better.
  • If E has a type S and the conversion from S to T1 is better than the conversion from S to T2, then C1 is the better conversion.
  • If E has a type S and the conversion from S to T2 is better than the conversion from S to T1, then C2 is the better conversion.
  • If E is an anonymous function, T1 and T2 are delegate types or expression tree types with identical parameter lists, and an inferred return type X exists for E in the context of that parameter list (§7.4.2.11):
    • if T1 has a return type Y1, and T2 has a return type Y2, and the conversion from X to Y1 is better than the conversion from X to Y2, then C1 is the better conversion.
    • if T1 has a return type Y1, and T2 has a return type Y2, and the conversion from X to Y2 is better than the conversion from X to Y1, then C2 is the better conversion.
    • if T1 has a return type Y, and T2 is void returning, then C1 is the better conversion.
    • if T1 is void returning, and T2 has a return type Y, then C2 is the better conversion.
    •  Otherwise, neither conversion is better.

到此为止我们找到了依据:由于Func<int,object>有返回object,因此它比Action<int>有更高的优先级。理解了这个我们很容易知道如果在上面的例子中再加入一个Test方法:

static void Test(Func<int, int> func)
{
     func(1);
}

那么他将比Func<int,object>具有更高优先级。经过测试,结果确实是这样。

注1:严格来讲我这里说的不准确。这样一个lambda表达式 i => { i = 1; } 可以是任何类型的委托,只要这个委托满足(1)接收一个int作为参数(2)没有返回值。你可以自己定义任意种这样的委托(当然它也可以是一个Action<int>)。

作者: 刀 刀 发表于 2011-02-21 02:54 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架