【问题标题】:C# Inline lambda evaluationC# 内联 lambda 评估
【发布时间】:2011-06-13 06:55:39
【问题描述】:

在使用 C# 编程的不同时间,我发现自己处于想要定义 lambda(或匿名委托)并在同一行中调用它的情况。在这一点上,我能够做到这一点的“最干净”的方式是这样的:

bool foo_equals_bar = new Func<String, bool>(str => str.Equals("foo"))("bar");

我希望能够写出类似以下的东西:

bool foo_equals_bar = (str => str.Equals("foo"))("bar");

不幸的是,这似乎不起作用。我很想知道:

  1. 上面这行代码有没有更简单的写法?
  2. (str =&gt; str.Equals("foo")) 返回的内容可以用于初始化Func&lt;String, bool&gt;,但不能像Func&lt;String, bool&gt; 一样进行评估?

我应该指出我正在使用 C# 3 (VS2008),所以如果解决方案仅存在于 C# 4 中,请提及。 (我仍然想知道,即使我目前无法获得解决方案)。

谢谢

【问题讨论】:

  • 这与"bar".Equals("foo") 有何不同?我知道这可能是简化的,但我没有看到您无法进行相同翻译的情况。
  • 我并不是想找到一种比较字符串的聪明方法,它只是一个简单的例子来展示原理(不幸的是,语法不正确)

标签: c# lambda


【解决方案1】:

您需要一组辅助方法来使编译器推断 lambda 类型,例如:

public static class Functional { public static Func<TResult> Lambda<TResult>(Func<TResult> func) { return func; } public static Func<T, TResult> Lambda<T, TResult>(Func<T, TResult> func) { return func; } public static Func<T1, T2, TResult> Lambda<T1, T2, TResult>(Func<T1, T2, TResult> func) { return func; } }

现在你可以写了:

bool foo_equals_bar = Functional.Lambda(str => str.Equals("foo"))("bar");

【讨论】:

  • 好主意。它本质上是创建 Func 类型并让编译器推断类型的语法糖。
  • 非常非常酷。方式被低估了。愿您为此获得许多赞成票。另外,从你为这个类选择的名字猜想,你有没有更妙的技巧让 C# 中的函数式编程更方便?
  • @sehe:好吧,这个技巧已经广为人知,但无论如何都要感谢。至于其他技巧,现在最有用的可能是 F# :) 它比在 C# 中模拟柯里化函数、无点样式、模式匹配和 ADT 之类的东西要好得多。我在 C# 中使用的另一个小东西是从 Action 委托到 Func 的转换器,这很容易通过使 lambda 返回 Object 或特殊的 Unit 类型来完成。
  • 至少在我的 LINQPad/C# 7 上,您的示例不起作用 - 它无法推断 str 的类型。
  • 我遇到了与@NetMage 相同的错误。我必须声明 str 的类型:bool foo_equals_bar = Functional.Lambda((string str) =&gt; str.Equals("foo"))("bar");
【解决方案2】:
str => str == "A" 

相同
delegate (string str) { return str == "A";};

所以不,没有办法只得到 lambda,因为如果你刚才说编译器不会知道 str 是什么类型

bool result = (str => str == "A")("B");

编辑:

是的,您可以向 lambda 表达式添加类型,例如 (string str) =&gt; str == "A";,但由于某种原因,它们仍然不能是隐式的。不知道为什么。谢谢你的评论,尤里。

【讨论】:

  • 在他的代码中是这样的。但问题是你不能有一个隐式的 lambda 表达式。你仍然可以使用(string str) =&gt; str.Equals("foo"),编译器会知道 str 是什么类型。
  • 编译器知道str是什么类型没有问题,问题在于推断委托类型,因为具有相同签名的委托在.NET中仍然是不同的类型。
  • 谢谢康斯坦丁 - 是的,现在你提到它很明显。即 Func 与 Predicate 相同,因此编译器无法知道您何时使用 (string s) => s == "A"
  • 我认为编辑有点误导,因为不能将 lambda (string str) =&gt; str == "A"; 分配给“简单”变量(例如 boolvar),而是分配给 Func&lt;string, bool&gt; 之类的变量(供参考,这里是Eric Lippert's explanation)。
【解决方案3】:

从 (str => 返回什么 str.Equals("foo")) 这样可以 用于初始化 Func,但不能像 功能?

仅使用内置类型,有:

Expression<Func<string, bool>> a = str => str.Equals("foo");
Expression<Predicate<string>> b = str => str.Equals("foo");
Expression<Action<string>> c = str => str.Equals("foo");
Func<string, bool> a1 = str => str.Equals("foo");
Predicate<string> b1 = str => str.Equals("foo");
Action<string> c1 = str => str.Equals("foo");

所有这些都是对 lambda 表达式的有效解释。这只是我能想到的内置类型。还有任何与签名匹配的委托。

【讨论】:

    【解决方案4】:

    在编程时的不同时间 C# 我发现自己陷入了困境 我想在哪里定义一个 lambda(或 匿名委托)并在 同一行。

    那些是奇怪的情况。避开他们。这是不可能的,因为编译器无法推断类型。当您将匿名委托传递给编译器可以从中推断类型的某个方法时,这可能会起作用。

    在任何情况下:

    bool foo_equals_bar = "bar".Equals("foo");
    

    *更具可读性:

    bool foo_equals_bar = (str => str.Equals("foo"))("bar");
    

    * 假设这样的语法是可能的

    【讨论】:

    • 是的,正如我在回答的评论中指出的那样,编译器没有理由无法弄清楚:bool result = ((string str) => str == "A" )("B"); - 我不知道为什么不支持它,但正如 Darian 所说,这无论如何都不是很可读。
    • 实际上,编译器确实可以推断类型,请参阅我的回答,了解如何使其做到这一点。没有此类帮助器,它无法推断类型,因为 .NET 中没有通用函数类型之类的东西,即它同样可以是 Func 和委托 bool MyCoolDelegateType(string str) 并且编译器不能喜欢其中之一他们。
    • 当然第一行比第二行更具可读性——如果我需要的只是一个简单的等式比较,我不会同时使用 lambda。该代码只是我所要求的一个简单示例。
    【解决方案5】:

    您必须将 lambda 转换为 func 或委托
    ((Func&lt;string, bool&gt;)(str =&gt; str.Equals("bar")))("baz")

    【讨论】:

      【解决方案6】:
      using System.Threading.Tasks;
      using System.Threading;
      
      Task.Run(()=>{
           //do something
      });
      

      您可以添加 500 毫秒的延迟

      Task.Run(()=>{
          Thread.Sleep(500);
          //do something
      });
      

      不确定 MS 何时添加,但不是 C#3

      这种编程风格可以完成任何事情,一旦你学会了这个,你基本上可以忽略其余的 C# 规范

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-05
        • 2017-04-27
        • 2020-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多