为什么不能将匿名方法赋值给 var?

发布于 2024-10-17 02:06:13 字数 685 浏览 1 评论 0原文

我有以下代码:

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

但是,以下代码无法编译:

var 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 个参数(在 .NET 3.5 中,这就是我正在使用的)。也许有人可以澄清这个问题。谢谢。

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>? 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 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). Perhaps someone could clarify the problem. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

燃情 2024-10-24 02:06:13

更新:这个答案是十多年前写的,应该被认为具有历史意义;在 C# 10 中,编译器将推断一些委托类型。


其他人已经指出,您可能指的是无限多种可能的委托类型; Func 有什么特别之处以至于它应该成为默认值,而不是 PredicateAction 或任何其他可能性?而且,对于 lambda 表达式,为什么很明显其意图是选择委托形式,而不是表达式树形式?

但我们可以说 Func 是特殊的,并且 lambda 或匿名方法的推断类型是某物的 Func。我们仍然会遇到各种各样的问题。对于以下情况,您希望推断出什么类型?

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

没有任何 Func 类型可以接受任何内容。

var x2 = y=>123;

尽管我们知道返回值,但我们不知道形式参数的类型。 (或者我们是吗?返回的是int?long?short?byte?)

var x3 = (int y)=>null;

我们不知道返回类型,但它不能为void。返回类型可以是任何引用类型或任何可为空的值类型。

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

同样,我们不知道返回类型,这次它可能为void。

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

这是一个返回 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 类型是什么。

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.


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? And, for lambdas, why is it obvious that the intention is to choose the delegate form, rather than the expression tree form?

But we could say that Func is special, and that the inferred type of a lambda or anonymous method is Func of something. 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.

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

var x3 = (int y)=>null;

We don't know the return type, but it can't be 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.

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? 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.

独自←快乐 2024-10-24 02:06:13

只有 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

编译器应该推断哪一个?没有充分的理由选择其中之一。尽管 Predicate 在功能上等同于 Func,但它们在 .NET 类型系统级别仍然是不同的类型。因此,编译器无法明确解析委托类型,并且类型推断必须失败。

Only Eric Lippert knows for sure, but I think it's because the signature of the delegate type doesn't uniquely determine the type.

Consider your example:

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

Here are two possible inferences for what the var should be:

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. The compiler therefore cannot unambiguously resolve the delegate type, and must fail the type inference.

花开浅夏 2024-10-24 02:06:13

Eric Lippert 有一个旧的 发布关于它,他说

实际上是 C# 2.0 规范
呼唤这一点。方法组
表达式和匿名方法
表达式是无类型表达式
在 C# 2.0 中,lambda 表达式连接
它们在 C# 3.0 中。因此它是
他们在网上“裸体”出现是违法的
隐式的右侧
声明。

Eric Lippert has an old post about it where he says

And in fact the C# 2.0 specification
calls this out. Method group
expressions and anonymous method
expressions are typeless expressions
in C# 2.0, and lambda expressions join
them in C# 3.0. Therefore it is
illegal for them to appear "naked" on
the right hand side of an implicit
declaration.

Hello爱情风 2024-10-24 02:06:13

不同的代表被视为不同的类型。例如,ActionMethodInvoker 不同,Action 的实例不能分配给 MethodInvoker 类型的变量代码>.

因此,给定一个像 () => 这样的匿名委托(或 lambda); {},它是 Action 还是 MethodInvoker?编译器无法判断。

同样,如果我声明一个带有 string 参数并返回 bool 的委托类型,编译器如何知道您确实想要一个 Func< /code> 而不是我的委托类型?它无法推断委托类型。

Different delegates are considered different types. e.g., Action is different than MethodInvoker, and an instance of Action can't be assigned to a variable of type MethodInvoker.

So, given an anonymous delegate (or lambda) like () => {}, is it an Action or a 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? It can't infer the delegate type.

羞稚 2024-10-24 02:06:13

以下几点来自 MSDN 关于隐式类型局部变量的内容:

  1. var 仅当在同一语句中声明和初始化局部变量时才能使用;该变量不能初始化为 null、方法组或匿名函数。
  2. var 关键字指示编译器从初始化语句右侧的表达式推断变量的类型。
  3. 重要的是要理解 var 关键字并不意味着“变体”,也不表示该变量是松散类型的或后期绑定的。它只是意味着编译器确定并分配最合适的类型。

MSDN 参考:隐式类型化局部变量

考虑以下有关匿名方法的内容:

  1. 匿名方法使您能够省略参数列表。

MSDN 参考:匿名方法

我怀疑,因为匿名方法可能实际上有不同的方法签名,编译器无法正确推断要分配的最合适的类型是什么。

The following points are from the MSDN regarding Implicitly Typed Local Variables:

  1. var can only be used when a local variable is declared and initialized in the same statement; the variable cannot be initialized to null, or to a method group or an anonymous function.
  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.
  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. It just means that the compiler determines and assigns the most appropriate type.

MSDN Reference: Implicitly Typed Local Variables

Considering the following regarding Anonymous Methods:

  1. Anonymous methods enable you to omit the parameter list.

MSDN Reference: Anonymous Methods

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.

隔纱相望 2024-10-24 02:06:13

我的帖子没有回答实际的问题,但它确实回答了以下根本问题:

“如何避免必须键入一些模糊的类型,例如 Func< /代码>?” [1]

作为一个懒惰/黑客的程序员,我尝试使用 Func - 它接受单个输入参数并返回一个对象。

对于多个参数,您可以像这样使用它:

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

提示:如果不需要返回对象,可以使用 Action

是的,我知道这可能违背你的编程原则,但这对我和一些 Python 程序员来说是有意义的。

我在代表方面还很新手……只是想分享我学到的东西。


[1] 这假设您没有调用需要预定义 Func 作为参数的方法,在这种情况下,您必须键入该模糊的字符串: /

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>?" [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.

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.

Yeah I know it probably goes against your programming principles, but this makes sense to me and probably some Python coders.

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 :/

春庭雪 2024-10-24 02:06:13

其他答案在编写时是正确的,但从 C# 10.0(从 2021 年起)开始,编译器可以推断出合适的委托类型(例如某些 Func<...>< /code>、Action<...> 或生成的委托类型)在这种情况下。

请参阅 C# 10 功能 - Lambda改进

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

当然,对我们来说更常用的语法是=>,所以:

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

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.

See C# 10 Features - Lambda improvements.

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
并安 2024-10-24 02:06:13

那个怎么样?

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

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);
零崎曲识 2024-10-24 02:06:13

我想在这里分享一下我的经验。

我有一个基于任务的 void 方法,并且我从其他地方调用该方法并将返回值存储在变量中。

我正在做这个测试目的,但后来我意识到这是一个无效的任务方法,并且它没有返回任何响应。

我删除了该变量存储代码并且它起作用了。

之前:

var test = wait function(argument1);

之后

等待函数(参数1);

I would like to share my experience over here.

I was having a Task based void method, and I was invoking that method from somewhere else and storing the return value in variable.

I was doing that test purpose, but later on I realized that it was a void task method and it is not returning any response.

I removed that variable storing code and it worked.

Before:

var test = await function(argument1);

After

await function(argument1);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文