代码改变世界

一个 有歧义 的 lambda 表达式

2009-11-11 21:22  鹤冲天  阅读(2735)  评论(27编辑  收藏  举报

 今天发现了一句有歧义的labmbda表达式,发出来供大家“把玩”。

 先看引起“是非争端”的两个扩展方法:

 1     public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
 2     {
 3         foreach (T t in source) action(t);
 4     }
 5 
 6     public static void ForEach<T>(this IEnumerable<T> source, Func<T, object> func)
 7     {
 8         foreach (T t in source) func(t);
 9     }

 第一个ForEach扩展不用多说;第二个比较怪吧,其实没必要存在,我也想不起来之前为什么就写了这么一个扩展。

 先别考虑第二个扩展的合理性,来看以下调用代码:

 1     public class People
 2     {
 3         public string Name { getset; }
 4         public int Age { getset; }
 5     }
 6 
 7     static public void Test()
 8     {
 9         People[] peoples = new People[]
10         {
11             new People { Name = "ldp615" },
12             new People { Name= "Tom" },
13             new People { Name ="Jim" }
14         };
15         peoples.ForEach(p => p.Age = 20);
16     }

 歧义在第15行,p => p.Age = 20。试问运行时会调用那个ForEach扩展呢??(先想想,答案在1楼

 

 两个ForEach,如果注释其中一个,代码同样能编译并运行,会自动匹配另外一个扩展。看来第15行有两重“含义”,如下:

1     peoples.ForEach(p => { p.Age = 20; });
2     peoples.ForEach(p => { return p.Age = 20; });

 以上两行代码中的lambda都可以简写成为 p => p.Age = 20,也就导致了歧义。

 

 那么在编译时,如何确定使用那个含义呢?应该看应用的上下文:

    1. 两个ForEach只保留一个时:使用与上下文相匹配的那含义(比较好理解)。
    2. 两个ForEach都存在时:我就不清楚了,可能是随机选一个吧,或者有优先级之说?(哪位高手知道,给俺说声)

 欢迎大家发表自己的看法。