简体   繁体   English

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

[英]Why can't an anonymous method be assigned to var?

I have the following code:我有以下代码:

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

However, the following does not compile:但是,以下内容无法编译:

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

Why can't the compiler figure out it is a Func<string, bool> ?为什么编译器无法确定它是Func<string, bool> It takes one string parameter, and returns a boolean.它接受一个字符串参数,并返回一个布尔值。 Instead, it gives me the error:相反,它给了我错误:

Cannot assign anonymous method to an implicitly-typed local variable.无法将匿名方法分配给隐式类型的局部变量。

I have one guess and that is if the var version compiled , it would lack consistency if I had the following:我有一个猜测,那就是如果 var 版本已编译,如果我有以下内容,它将缺乏一致性:

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

The above wouldn't make sense since Func<> allows only up to 4 arguments (in .NET 3.5, which is what I am using).以上没有意义,因为 Func<> 最多只允许 4 个参数(在 .NET 3.5 中,这是我正在使用的)。 Perhaps someone could clarify the problem.也许有人可以澄清这个问题。 Thanks.谢谢。

UPDATE: This answer was written over ten years ago and should be considered to be of historical interest;更新:这个答案是十多年前写的,应该被认为具有历史意义; in C# 10 the compiler will infer some delegate types.在 C# 10 中,编译器会推断出一些委托类型。


Others have already pointed out that there are infinitely many possible delegate types that you could have meant;其他人已经指出,您可能意味着有无数种可能的委托类型; what is so special about Func that it deserves to be the default instead of Predicate or Action or any other possibility? Func有什么特别之处以至于它应该成为默认值而不是PredicateAction或任何其他可能性? And, for lambdas, why is it obvious that the intention is to choose the delegate form, rather than the expression tree form?而且,对于 lambdas,为什么选择委托形式而不是表达式树形式很明显?

But we could say that Func is special, and that the inferred type of a lambda or anonymous method is Func of something.但是我们可以说Func是特殊的,lambda 或匿名方法的推断类型是某物的 Func。 We'd still have all kinds of problems.我们仍然会遇到各种各样的问题。 What types would you like to be inferred for the following cases?对于以下情况,您希望推断出哪些类型?

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

There is no Func<T> type that takes a ref anything.没有Func<T>类型可以使用 ref 任何东西。

var x2 = y=>123;

We don't know the type of the formal parameter, though we do know the return.我们不知道形参的类型,尽管我们知道返回值。 (Or do we? Is the return int? long? short? byte?) (或者我们呢?返回的是 int?long?short?byte?)

var x3 = (int y)=>null;

We don't know the return type, but it can't be void.我们不知道返回类型,但它不能为 void。 The return type could be any reference type or any nullable value type.返回类型可以是任何引用类型或任何可为空的值类型。

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

Again, we don't know the return type, and this time it can be void.同样,我们不知道返回类型,这一次它可能是 void。

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

Is that intended to be a void-returning statement lambda or something that returns the value that was assigned to q?那是打算成为返回无效语句 lambda 还是返回分配给 q 的值的东西? Both are legal;两者都是合法的; which should we choose?我们应该选择哪个?

Now, you might say, well, just don't support any of those features.现在,您可能会说,好吧,只是不支持任何这些功能。 Just support "normal" cases where the types can be worked out.只支持可以计算类型的“正常”情况。 That doesn't help.那没有帮助。 How does that make my life easier?这如何让我的生活更轻松? If the feature works sometimes and fails sometimes then I still have to write the code to detect all of those failure situations and give a meaningful error message for each.如果该功能有时有效,有时失败,那么我仍然必须编写代码来检测所有这些失败情况并为每种情况提供有意义的错误消息 We still have to specify all that behaviour, document it, write tests for it, and so on.我们仍然必须指定所有这些行为、记录它、为其编写测试等等。 This is a very expensive feature that saves the user maybe half a dozen keystrokes.这是一个非常昂贵的功能,可以为用户节省大约六次击键。 We have better ways to add value to the language than spending a lot of time writing test cases for a feature that doesn't work half the time and doesn't provide hardly any benefit in cases where it does work.我们有更好的方法来增加语言的价值,而不是花费大量时间为一个在一半时间不起作用并且在它起作用的情况下几乎没有任何好处的功能编写测试用例。

The situation where it is actually useful is:它实际有用的情况是:

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

because there is no "speakable" type for that thing.因为那个东西没有“可说”的类型。 But we have this problem all the time, and we just use method type inference to deduce the type:但是我们一直有这个问题,我们只是使用方法类型推断来推断类型:

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

and now method type inference works out what the func type is.现在方法类型推断可以确定 func 类型是什么。

Only Eric Lippert knows for sure, but I think it's because the signature of the delegate type doesn't uniquely determine the type.只有 Eric Lippert 肯定知道,但我认为这是因为委托类型的签名并不能唯一地确定类型。

Consider your example:考虑你的例子:

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

Here are two possible inferences for what the var should be:对于var应该是什么,这里有两个可能的推论:

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

Which one should the compiler infer?编译器应该推断哪一个? There's no good reason to choose one or the other.没有充分的理由选择其中之一。 And although a Predicate<T> is functionally equivalent to a Func<T, bool> , they are still different types at the level of the .NET type system.尽管Predicate<T>在功能上等同于Func<T, bool> ,但它们在 .NET 类型系统级别上仍然是不同的类型。 The compiler therefore cannot unambiguously resolve the delegate type, and must fail the type inference.因此,编译器无法明确解析委托类型,并且必须使类型推断失败。

Eric Lippert has an old post about it where he says Eric Lippert 有一篇关于它的旧帖子,他说

And in fact the C# 2.0 specification calls this out.事实上,C# 2.0 规范对此进行了说明。 Method group expressions and anonymous method expressions are typeless expressions in C# 2.0, and lambda expressions join them in C# 3.0.方法组表达式和匿名方法表达式在 C# 2.0 中是无类型表达式,而 lambda 表达式在 C# 3.0 中加入了它们。 Therefore it is illegal for them to appear "naked" on the right hand side of an implicit declaration.因此,它们在隐式声明的右侧出现“裸体”是非法的。

Different delegates are considered different types.不同的代表被认为是不同的类型。 eg, Action is different than MethodInvoker , and an instance of Action can't be assigned to a variable of type MethodInvoker .例如, ActionMethodInvoker不同,并且Action的实例不能分配给MethodInvoker类型的变量。

So, given an anonymous delegate (or lambda) like () => {} , is it an Action or a MethodInvoker ?那么,给定一个像() => {}这样的匿名委托(或 lambda),它是Action还是MethodInvoker The compiler can't tell.编译器无法判断。

Similarly, if I declare a delegate type taking a string argument and returning a bool , how would the compiler know you really wanted a Func<string, bool> instead of my delegate type?同样,如果我声明一个接受string参数并返回bool的委托类型,编译器怎么知道你真的想要一个Func<string, bool>而不是我的委托类型? It can't infer the delegate type.它无法推断委托类型。

The following points are from the MSDN regarding Implicitly Typed Local Variables:以下几点来自 MSDN 关于隐式类型局部变量:

  1. var can only be used when a local variable is declared and initialized in the same statement; var 只能在同一语句中声明和初始化局部变量时使用; the variable cannot be initialized to null, or to a method group or an anonymous function.变量不能初始化为 null,也不能初始化为方法组或匿名函数。
  2. The var keyword instructs the compiler to infer the type of the variable from the expression on the right side of the initialization statement. var 关键字指示编译器从初始化语句右侧的表达式推断变量的类型。
  3. It is important to understand that the var keyword does not mean "variant" and does not indicate that the variable is loosely typed, or late-bound.重要的是要理解 var 关键字并不意味着“变体”,也不表示该变量是松散类型或后期绑定的。 It just means that the compiler determines and assigns the most appropriate type.它只是意味着编译器确定并分配最合适的类型。

MSDN Reference: Implicitly Typed Local Variables MSDN 参考:隐式类型的局部变量

Considering the following regarding Anonymous Methods:考虑以下有关匿名方法的内容:

  1. Anonymous methods enable you to omit the parameter list.匿名方法使您能够省略参数列表。

MSDN Reference: Anonymous Methods MSDN 参考:匿名方法

I would suspect that since the anonymous method may actually have different method signatures, the compiler is unable to properly infer what the most appropriate type to assign would be.我怀疑由于匿名方法实际上可能具有不同的方法签名,编译器无法正确推断出最合适的分配类型。

My post doesn't answer the actual question, but it does answer the underlying question of :我的帖子没有回答实际问题,但确实回答了以下基本问题:

"How do I avoid having to type out some fugly type like Func<string, string, int, CustomInputType, bool, ReturnType> ?" “我如何避免输入一些像Func<string, string, int, CustomInputType, bool, ReturnType>这样的丑陋类型?” [1] [1]

Being the lazy/hacky programmer that I am, I experimented with using Func<dynamic, object> - which takes a single input parameter and returns an object.作为懒惰/hacky 的程序员,我尝试使用Func<dynamic, object> - 它采用单个输入参数并返回一个对象。

For multiple arguments, you can use it like so:对于多个参数,您可以像这样使用它:

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

Tip: You can use Action<dynamic> if you don't need to return an object.提示:如果不需要返回对象,可以使用Action<dynamic>

Yeah I know it probably goes against your programming principles, but this makes sense to me and probably some Python coders.是的,我知道这可能违背了你的编程原则,但这对我和一些 Python 编码员来说是有意义的。

I'm pretty novice at delegates... just wanted to share what I learned.我是代表的新手......只是想分享我学到的东西。


[1] This assumes that you aren't calling a method that requires a predefined Func as a parameter, in which case, you'll have to type that fugly string :/ [1]这假设您没有调用需要预定义的Func作为参数的方法,在这种情况下,您必须键入该丑陋的字符串:/

Other answers were correct at the time they were written, but starting from C# 10.0 (from 2021), the compiler can infer a suitable delegate type (like some Func<...> , Action<...> or generated delegate type) in such cases.其他答案在编写时是正确的,但从 C# 10.0(从 2021 年开始)开始,编译器可以推断出合适的委托类型(如某些Func<...>Action<...>或生成的委托类型)在这种情况下。

See C# 10 Features - Lambda improvements .请参阅C# 10 功能 - Lambda 改进

var comparer = delegate(string value) {
    return value != "0";
};   // OK in C# 10.0, picks 'Func<string, bool>' in this case

Of course the more usual syntax is to us => , so:当然,更常用的语法是我们=> ,所以:

var comparer = (string value) => {
    return value != "0";
};   // OK in C# 10.0, picks 'Func<string, bool>' in this case

How is about that?怎么样?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C# 为什么我们不能将委托匿名方法分配给 var 关键字 - C# Why can't we assign delegate anonymous method to var key word 无参数匿名方法可以分配给有参数委托 - Parameterless anonymous method can be assigned to parametered delegate 可以将委托分配给匿名方法或lambda,但不分配给方法 - Delegate can be assigned to either anonymous method or lambda but not to a method 在 C# 中,为什么匿名方法不能包含 yield 语句? - In C#, why can't an anonymous method contain a yield statement? 为什么我不能在匿名方法中的while循环中使用break? - Why can't I use break in a while loop in an anonymous method? 为什么不能在其创建方法之外使用匿名类型? - Why can't an Anonymous Type be used outside the method it's created in? 为什么不能通过没有&#39;out&#39;的方法来分配Texture2D? - Why can't a Texture2D be assigned through a method without 'out'? 为什么在这种情况下不能使用var? - Why can't I use var in this instance? 为什么我不能用 var 隐式转换? - Why can’t I implicitly convert with var? 为什么我不能在调试器中编辑包含匿名方法的方法? - Why can I not edit a method that contains an anonymous method in the debugger?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM