为什么不能将一个匿名方法分配给var?

我有以下代码:

Func<string, bool> comparer = delegate(string value) { return value != "0"; }; 

但是,下面不编译:

 var comparer = delegate(string value) { return value != "0"; }; 

为什么编译器不知道它是一个Func<string, bool> ? 它接受一个string参数,并返回一个布尔值。 相反,它给了我错误:

无法将匿名方法分配给隐式types的本地variables。

我有一个猜测,那就是如果var版本编译 ,它会缺乏一致性,如果我有以下几点:

 var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) { return false; }; 

以上是没有意义的,因为Func <>只允许最多4个参数(在.NET 3.5中,这是我使用的)。 也许有人可以澄清这个问题。 谢谢。

其他人已经指出,你可能意味着有无数的可能的委托types; Func有什么特别的地方,它应该是默认的,而不是Predicate或者Action或者其他的可能性? 而对于lambdas,为什么显而易见的是select委托forms,而不是expression式树forms?

但是我们可以说Func是特殊的,lambda或匿名方法的推断types是Func。 我们仍然有各种各样的问题。 对于以下情况,您希望推断哪些types?

 var x1 = (ref int y)=>123; 

没有任何Func<T>types需要ref。

 var x2 = y=>123; 

我们不知道forms参数的types,虽然我们知道返回。 (或者我们?是返回int?long?short?byte?)

 var x3 = (int y)=>null; 

我们不知道返回types,但不能是无效的。 返回types可以是任何引用types或任何可为null的值types。

 var x4 = (int y)=>{ throw new Exception(); } 

再次,我们不知道返回types,这次可能是无效的。

 var x5 = (int y)=> q += y; 

这是打算是一个返回void的语句lambda或返回分配给q的值的东西吗? 两者都是合法的; 我们应该select哪一个?

现在,你可能会说,只是不支持任何这些function。 只要支持可以计算出types的“正常”情况。 这没有帮助。 这是如何让我的生活更轻松? 如果这个特性有时会起作用而且有时候会失败,那么我仍然需要编写代码来检测所有这些失败情况,并给出一个有意义的错误信息 。 我们仍然必须指定所有的行为,logging它,为它写testing,等等。 这是一个非常昂贵的function ,可以节省用户大概六打击键。 我们有更好的方法来增加语言的价值,而不是花费大量的时间编写testing用例,这个function在一半时间不工作,并且在其工作情况下几乎没有任何好处。

实际上有用的情况是:

 var xAnon = (int y)=>new { Y = y }; 

因为那个东西没有“朗读”types。 但是我们一直都有这个问题,我们只是使用方法types推断来推导出types:

 Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; } ... var xAnon = WorkItOut((int y)=>new { Y = y }); 

现在方法types推断可以确定functypes是什么。

只有Eric Lippert知道,但我认为这是因为委托types的签名并不唯一确定types。

考虑你的例子:

 var comparer = delegate(string value) { return value != "0"; }; 

这里有两个可能的推断什么var应该是:

 Predicate<string> comparer = delegate(string value) { return value != "0"; }; // okay Func<string, bool> comparer = delegate(string value) { return value != "0"; }; // also okay 

编译器应该推断哪一个? 没有理由select一个或另一个。 尽pipePredicate<T>在function上等价于Func<T, bool> ,但它们在.NETtypes系统的层次上仍然是不同的types。 因此,编译器无法明确地parsing委托types,并且必须使types推断失败。

埃里克·利珀特(Eric Lippert)在他的讲话中有一个旧post

事实上,C#2.0规范就是这样调用的。 方法组expression式和匿名方法expression式在C#2.0中是无typesexpression式,lambdaexpression式将它们join到C#3.0中。 因此,他们在隐式声明的右边出现“裸体”是非法的。

不同的代表被认为是不同的types。 例如, ActionMethodInvoker不同, Action的实例不能分配给MethodInvokertypes的variables。

所以,给定一个匿名委托(或lambda)like () => {} ,它是一个Action还是一个MethodInvoker ? 编译器不能告诉。

同样,如果我声明一个采用string参数的委托types并返回一个bool ,编译器如何知道你真的想要一个Func<string, bool>而不是我的委托types? 它不能推断委托types。

以下几点来自MSDN:隐式types局部variables:

  1. var只能在局部variables在同一个语句中声明和初始化时使用; 该variables不能被初始化为空,或者方法组或匿名函数。
  2. var关键字指示编译器从初始化语句右侧的expression式推断variables的types。
  3. 了解var关键字并不意味着“变体”,并且不表示该variables是松散types的,或者是后期绑定的。 这只是意味着编译器确定并分配最合适的types。

MSDN参考:隐式键入的局部variables

考虑以下关于匿名方法:

  1. 匿名方法使您可以省略参数列表。

MSDN参考:匿名方法

我怀疑由于匿名方法实际上可能有不同的方法签名,因此编译器无法正确推断出最适合的types。

这是怎么回事?

 var item = new { toolisn = 100, LangId = "ENG", toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId) { var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html"; return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : ""; } }; string result = item.toolPath(item.toolisn, item.LangId);