C# 为什么可以';不能将匿名方法分配给var吗?
我有以下代码:C# 为什么可以';不能将匿名方法分配给var吗?,c#,.net-3.5,delegates,lambda,implicit-typing,C#,.net 3.5,Delegates,Lambda,Implicit Typing,我有以下代码: Func<string, bool> comparer = delegate(string value) { return value != "0"; }; 为什么编译器不能找出它是一个Func?它接受一个字符串参数,并返回一个布尔值。相反,它给了我一个错误: 无法将匿名方法分配给 隐式类型局部变量 我有一个猜测,如果编译了var版本,那么如果我有以下内容,它将缺乏一致性: var comparer = delegate(string arg1, strin
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
为什么编译器不能找出它是一个Func
?它接受一个字符串参数,并返回一个布尔值。相反,它给了我一个错误:
无法将匿名方法分配给
隐式类型局部变量
我有一个猜测,如果编译了var版本,那么如果我有以下内容,它将缺乏一致性:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
上述内容没有意义,因为Func最多只允许4个参数(在.NET3.5中,这就是我正在使用的)。也许有人可以澄清这个问题。谢谢。不同的代表被视为不同的类型。e、 例如,
Action
不同于MethodInvoker
,并且不能将Action
的实例分配给类型为MethodInvoker
的变量
那么,给定像()=>{}
这样的匿名委托(或lambda),它是操作还是方法调用程序
?编译器不知道
类似地,如果我使用字符串
参数声明一个委托类型,并返回一个bool
,编译器怎么知道您真正想要的是Func
,而不是我的委托类型?它无法推断委托类型。只有Eric Lippert可以肯定,但我认为这是因为委托类型的签名并不是唯一确定类型的
以你的例子为例:
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
谓词比较器=委托(字符串值){返回值!=“0”};//可以
Func comparer=delegate(字符串值){返回值!=“0”};//还可以
编译器应该推断哪一个?没有很好的理由选择其中一个。尽管谓词
在功能上等同于函数
,但它们在.NET类型系统级别上仍然是不同的类型。因此,编译器无法明确地解析委托类型,并且必须使类型推断失败。Eric Lippert对此有一个古老的看法,他说
事实上,C#2.0规范
这就是我要说的。方法组
表达式和匿名方法
表达式是无类型表达式
在C#2.0中,和lambda表达式连接
他们在C#3.0中。因此它是
他们在电视上“裸体”是违法的
隐式表达式的右侧
声明
以下是MSDN中关于隐式类型局部变量的要点:
只有在同一语句中声明并初始化局部变量时,才能使用var;无法将变量初始化为null、方法组或匿名函数
var关键字指示编译器从初始化语句右侧的表达式推断变量的类型
重要的是要理解var关键字并不表示“variant”,也不表示变量是松散类型的,或者是后期绑定的。这只意味着编译器确定并分配最合适的类型
考虑以下关于匿名方法的问题:
匿名方法允许您省略参数列表
我怀疑,由于匿名方法实际上可能具有不同的方法签名,编译器无法正确推断最适合分配的类型。其他人已经指出,您可能指的委托类型有无限多;Func
有什么特别之处,它应该成为默认值,而不是谓词
或动作
或任何其他可能性?而且,对于lambdas,为什么很明显的意图是选择委托形式,而不是表达式树形式
但是我们可以说Func
是特殊的,并且lambda或匿名方法的推断类型是Func。我们仍然会有各种各样的问题。对于以下情况,您希望推断哪些类型
var x1 = (ref int y)=>123;
没有接受任何引用的Func
类型
var x2 = y=>123;
我们不知道形式参数的类型,尽管我们知道返回值。(还是我们?返回的int是长字节还是短字节?)
我们不知道返回类型,但不能为空。返回类型可以是任何引用类型或任何可为null的值类型
var x4 = (int y)=>{ throw new Exception(); }
同样,我们不知道返回类型,这次它可能是无效的
这是一个void返回语句lambda还是一个返回分配给q的值的语句?两者都是合法的;我们应该选择哪一个
现在,你可能会说,只是不支持这些功能。只需支持“正常”情况,即可计算出类型。那没用。这怎么让我的生活更轻松?如果该功能有时工作,有时失败,那么我仍然必须编写代码来检测所有这些失败情况,并为每个情况提供有意义的错误消息。我们仍然需要指定所有这些行为,记录它,为它编写测试,等等。这是一项非常昂贵的功能,可以为用户节省大约六次击键。我们有更好的方法来增加语言的价值,而不是花大量时间为一个功能编写测试用例,这个功能一半的时间都不起作用,而且在它起作用的情况下几乎没有任何好处
实际有用的情况是:
var xAnon = (int y)=>new { Y = y };
因为那东西没有“可说出”的类型。但我们一直都有这个问题,我们只是使用方法类型推断来推断类型:
Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
Func WorkItOut(Func f){return f;}
...
var xAnon=WorkItOut((inty)=>new{y=y});
现在,方法类型推断计算出func类型是什么。这是怎么回事
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);
var项=新建
{
工具编号=100,
LangId=“ENG”,
工具路径=(Func)委托(int-toolsn,string-LangId)
{
变量路径
var xAnon = (int y)=>new { Y = y };
Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
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);
dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));