Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以';不能将匿名方法分配给var吗?_C#_.net 3.5_Delegates_Lambda_Implicit Typing - Fatal编程技术网

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));