【问题标题】:Lambda Expression definition (pedant )?Lambda 表达式定义(学究)?
【发布时间】:2012-12-20 12:48:07
【问题描述】:

通过简单介绍一本书(领先一本书),有一件事引起了我的注意——lambda表达式定义:

lambda 表达式是一个未命名的方法,用于代替 委托实例。

代替委托实例???

委托实例是一个引用/封装目标方法的对象

在以下示例中,右侧(lambda 表达式所在的位置)不是委托实例。这是一种方法。

TransformerDelegate t = SquareMethod;

所以定义应该已经更正/提及:

lambda 表达式是代替方法编写的未命名方法(!) 被委托变量引用。

TransformerDelegate sqr = x => x * x;
                              ^
                              |
               ---------------+
               |

            this is the location for method/anonymous methods.

你明白我的意思吗?我说的对吗?

附言我确实了解了msdn的:(但想看看这本书是否有错误)

lambda 表达式是一个匿名函数,它可以包含 表达式和语句,可用于创建委托或 表达式树类型。

【问题讨论】:

  • 你对这种微妙的问题有敏锐的眼光;你是正确的,措辞是不优雅和不准确的,即使它得到了正确的想法。如果您仔细阅读技术书籍,您会很快发现很多此类问题;例如,即使是经验丰富的作家也会将“对象”与“变量”混淆。我编辑过的唯一一本几乎每次都正确使用技术术语的书当然是C# in Depth。 :-)
  • @EricLippert 谢谢埃里克 :-)
  • Pedantry:在声明TransformerDelegate t = SquareMethod;中,SquareMethod不是一个方法,它是一个方法组
  • @phoog 为什么说它是一个方法组? TransformerDelegate type 有一个严格的定义。例如:public delegate int TransformerDelegate (int a) 它只会对整数执行。您的意思是它可以用较少派生的类型执行吗?但是 derived 比 int 少吗?
  • Eric Lippert 可能会在这里纠正我,但我认为@phoog 的意思是 SquareMethod 这个名字可以是几个重载的方法,因此即使在这种情况下它只是一个方法,它也被称为 MethodGroup。 (只有一个重载的方法可以匹配委托签名,所以只有一个被添加到委托)

标签: c# .net delegates lambda


【解决方案1】:

lambda 表达式的值一个委托实例。

所以这本书可能指的是这样的代码:

MySquareDelegate f1 = x => x * x;
MySquareDelegate f2 = new MySquareDelegate(MySquareMethod);
MySquareDelegate f3 = MySquareMethod;  // just shorthand for the previous line

很难用 1 句话解释,你自己的版本

lambda 表达式是代替委托变量引用的方法(!)编写的未命名方法。

是在谈论“方法而不是方法”,原来是关于“方法而不是委托实例”,其中方法被隐式转换为委托实例。至少两者似乎都不完整。

lambda 的定义还应该包括它是一个 内联 方法。

【讨论】:

  • +1 是有道理的。在我的脑海中是MySquareDelegate f2 = MySquareMethod,而右侧只是一种方法。但是老式的方式(使用 new() )澄清了事情。谢谢 。所以这本书没有错。
【解决方案2】:

其他答案忽略了 lambda 表达式不一定代表方法这一事实。有时,它们代表表达式树。

编译器会根据上下文将 lambda 表达式隐式转换为一种或另一种对象。

要指定方法,需要指定参数和主体。在 lambda 表达式中,它们由 => 分隔。例子:

    ()     => 4;               //empty parameter list
    x      => x.ToString();    //one parameter
    (a, b) => a.Equals(b);     //two parameters
//  ^^^^^^    ^^^^^^^^^^^^
//  |                    |
//  parameter list       body

这些 lambda 表达式可以分别转换为 Func<int>Func<object, string>Func<object, object, bool>。也可以分别转换为Expression<Func<int>>Expression<Func<object, string>>Expression<Func<object, object, bool>>

匿名方法:

delegate (object p, object q) { return string.Concat(p, q); }
//       ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//       parameter list       body

以下是 lambda 转换的两个示例:

Func<object, object, bool> aDelegate = (o1, o2) => object.Equals(o1, o2);
Expression<Func<object, object, bool>> anExpressionTree = (o1, o2) => object.Equals(o1, o2);

在方法组转换中,参数和方法体由重载决议指定。为了简化一点,编译器查看具有指定名称的方法并根据上下文选择正确的重载。例如,考虑 SquareMethod 的这些重载:

int SquareMethod(int a) { return a * a; }
double SquareMethod(double a) { return a * a; } 

这些语句涉及方法组转换和重载解析:

Func<int, int> squareAnInt = SquareMethod;
Func<double, double> squareADouble = SquareMethod;

最后,无法将语句 lambda 转换为表达式树:

Action<object> anAction = o => { Console.WriteLine(o); };
Func<object, int> aFunc = o =>
    {
        var s = (o ?? "").ToString();
        Console.WriteLine(s);
        return s.Length;
    };

C# 语言规范(有些混乱)使用术语“匿名函数”来涵盖 lambda 表达式和匿名方法。匿名函数可以隐式转换为兼容的委托类型,方法组也可以。因此,如果我们有一个名为 DelegateType 的委托类型,以及这样的声明/赋值:

DelegateType d = [something];

那么[something]可以是方法组或匿名函数。换句话说,它可以是方法组、匿名方法或 lambda 表达式。

因此,您对书中文字的更正最好说“代替方法组”,但我会说

lambda 表达式是一种未命名方法,与命名方法组一样,可用于创建委托实例。

我也可以添加

在某些情况下,lambda 表达式可用于创建表达式树而不是委托实例。

【讨论】:

    【解决方案3】:

    基本上,委托只不过是一个知道如何调用特定方法的对象。因此,委托instance实际上充当调用者的委托:调用者调用委托,然后委托调用目标方法。

    【讨论】:

    • “对象由编译器构建”有点掩盖了细节,不是吗?该对象是在运行时构建的,而不是在编译时构建的。
    猜你喜欢
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多