【问题标题】:Execute lambda expression immediately after its definition?在定义后立即执行 lambda 表达式?
【发布时间】:2012-04-17 20:09:52
【问题描述】:

有没有办法在定义后立即执行 lambda 表达式?

换句话说(无效的 C# 代码):

(() => { Console.WriteLine("Hello World"); }).Invoke();

【问题讨论】:

  • 等等……什么?为什么是 lambda 表达式?
  • 你的代码无效的原因是你没有告诉编译器你想要Action还是Expression<Action>。如果您将该 lambda 表达式转换为 Action,您将能够对其调用 Invoke 或使用方法调用语法 () 来调用它。
  • 我的想象力可能让我失望了,真的有必要这样做吗?
  • 知道了。现在说得通了。 @Tejs 的回答非常清楚。
  • 这是一种更实用的代码形式,它清楚地定义了当前方法的哪一部分仅用于一项任务。不一定更有效,但我已经使用它来隔离代码,而无需将其分解为具有所有范围问题的新函数。

标签: c# lambda


【解决方案1】:

当然。

new Action(() => { Console.WriteLine("Hello World"); })();

这应该可以解决问题。

【讨论】:

    【解决方案2】:

    另一个“选项”,这只是另外两个答案,形式略有不同:

    ((Action)(() => { Console.WriteLine("Hello World"); }))();
    

    原因,直接取自 phoog 的评论

    ...您还没有告诉编译器您想要Action 还是Expression<Action>。如果您将该 lambda 表达式转换Action,您将能够对其调用 Invoke 或使用方法调用语法 () 来调用它。

    它确实变得丑陋了,而且我不知道这种形式在哪里有用,因为它不能用于没有名称的递归......

    【讨论】:

    • 您完全可以使用 Y 组合器进行递归:public delegate T Recursive<T>(Recursive<T> f, T n); static void Main(string[] args) { System.Console.WriteLine("Factorial 5 = {0}", new Recursive<int>((f, n) => f(f, n))(new Recursive<int>((f, n) => (n == 0) ? 1 : n * f(f, n - 1)), 5)); }。这是来自纯函数世界的 hack,它基本上声明了一个函数 f 将自己作为参数,并通过传递 f 递归调用自己。为了开始递归,这个函数被传递给另一个调用 f 并带有 f 和参数初始值的函数。
    • 我发现这对于从非异步函数执行等待很有用: ((Action)(async () => { x = await task; }))();我能够声明 lambda async 并立即调用它。
    【解决方案3】:

    你应该可以这样做:

    Action runMe = () => { Console.WriteLine("Hello World"); };
    runMe();
    

    【讨论】:

    • 正确。编译器会将 lambda 语法解释为委托的简写。只有当您分配到 Expression<Delegate> 类型时,它才会构造表达式树。
    • 这不会编译,因为编译器无法确定您需要Action 还是Expression<Action>
    • @phoog 是正确的。这不会编译。 “无法将 lambda 表达式分配给隐式类型的局部变量。”
    【解决方案4】:

    这是一个如何使用它的示例。您希望使用无法编写为函数的几行代码的结果来初始化构造函数,因为这就是第 3 方 API 的结构。

    这只是粘合代码,以防止编写一个从未在其他任何地方调用过的独立函数。我用的是Func而不是Action,但是答案和user166390一样。

            // imagine several dozens of lines that look like this
            // where the result is the return value of a function call
            fields.Add(new ProbeField(){ 
                Command = "A",
                Field = "Average",
                Value = be.GetAverage()
            });
    
            // now you need something that can't be expressed as function call
            // so you wrap it in a lambda and immediately call it.
            fields.Add(new ProbeField(){ 
                Command = "C",
                Field = "Cal Coeff",
                Value = ((Func<string>)(() => {
                    CalCoef coef;
                    Param param;
                    be.GetCalibrationCoefficients(out coef, out param);
                    return coef.lowDet1.ToString();
                }))()
            });
    

    【讨论】:

      【解决方案5】:

      对于我自己的项目,我有时会编写一个很小的可重用辅助函数,以使立即调用的 lambda 的语法看起来更短。这个“Inv”的灵感来自于 LanguageExt 库中类似的“fun”函数。

      // Helper utility functions
      public static void Inv(Action a) => a();
      public static T Inv<T>(Func<T> f) => f();
      
      private static void TestMethod()
      {
          // Action example
          Inv(() => Console.WriteLine("Hello World!"));
          // Func example with no parameters
          bool result = Inv(() =>
          {
              if (1 == 1)
                  return true;
              else
                  return false;
          });
      }
      

      你也可以用一些其他的重载来扩展它,这样你就可以传入参数,但是这些在语法上看起来有点麻烦,可能没有那么有用。

      public static Func<A, T> Inv<A, T>(Func<A, T> f) => f;
      public static Func<A, B, T> Inv<A, B, T>(Func<A, B, T> f) => f;
      
      string printNumber = Inv((int number) => $"This is the number {number}")(5);
      int addedNumbers = Inv((int x, int y) => x + y)(5, 6);
      

      【讨论】:

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

        程序员真的很喜欢让事情变得比他们应该做的更困难

        您可以添加 500 毫秒的延迟

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

        然后下一个逻辑扩展是将参数传递给您的匿名函数。您可以使用范围:

        var x=1;
        Task.Run(()=>{
            x++;
        });
        

        然后您基本上可以将 C# 的其余部分扔出窗外。如果你喜欢这种函数式风格,我建议使用 JS 或 C。

        【讨论】:

          猜你喜欢
          • 2020-09-11
          • 2017-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多