代码之家  ›  专栏  ›  技术社区  ›  Binoj Antony

何时不使用lambda表达式[关闭]

  •  51
  • Binoj Antony  · 技术社区  · 17 年前

    stackoverflow上回答了许多问题,成员指定如何使用 lambda expressions .

    我们是否过度使用了它,是否考虑了使用lambda表达式对性能的影响?

    我发现一些文章探讨了lambda与匿名委托vs for / foreach 具有不同结果的循环

    1. Anonymous Delegates vs Lambda Expressions vs Function Calls Performance
    2. Performance of foreach vs. List.ForEach
    3. .NET/C# Loop Performance Test (FOR, FOREACH, LINQ, & Lambda) .
    4. DataTable.Select is faster than LINQ

    在选择合适的解决方案时,评估标准应该是什么?除了明显的原因,它更简洁的代码和可读性时使用lambda。

    9 回复  |  直到 9 年前
        1
  •  32
  •   Dan Atkinson    8 年前

    尽管我会把重点放在第一点上,但我首先要在整个表现问题上付出2美分。除非差异很大或使用量很大,否则通常我不关心微秒,因为添加微秒对用户来说不等于任何可见的差异。我强调,我只是在考虑非密集调用方法时才不在乎。在设计应用程序本身的过程中,我确实有特殊的性能考虑。我关心缓存、线程的使用、调用方法的聪明方法(是多次调用还是只尝试一次调用)、是否池连接等等。事实上,我通常不关注原始性能,而是关注可伸缩性。我不在乎对于一个用户来说,它的运行速度是否能提高一纳秒,但我非常关心是否有能力在不注意影响的情况下为系统加载大量的同时用户。

    话虽如此,以下是我对第一点的看法。我喜欢匿名的方法。它们给了我很大的灵活性和代码的优雅性。匿名方法的另一个重要特性是,它们允许我直接使用容器方法中的局部变量(当然是从c的角度,而不是从il的角度)。他们经常给我留下大量的代码。我什么时候使用匿名方法?每次我需要的代码在其他地方都不需要。如果在两个不同的地方使用,我不喜欢复制粘贴作为重用技术,所以我将使用一个普通的ol'delegate。所以,就像shoosh回答的那样,有代码复制是不好的。理论上没有性能差异,因为匿名是C技巧,而不是IL的东西。

    我认为匿名方法的大部分内容都适用于lambda表达式,因为后者可以用作表示匿名方法的紧凑语法。我们假设以下方法:

    public static void DoSomethingMethod(string[] names, Func<string, bool> myExpression)
    {
        Console.WriteLine("Lambda used to represent an anonymous method");
        foreach (var item in names)
        {
            if (myExpression(item))
                Console.WriteLine("Found {0}", item);
        }
    }
    

    它接收一个字符串数组,并为每个字符串调用传递给它的方法。如果该方法返回true,它将显示“found…”。你可以用以下方法调用这个方法:

    string[] names = {"Alice", "Bob", "Charles"};
    DoSomethingMethod(names, delegate(string p) { return p == "Alice"; });
    

    但是,你也可以这样称呼它:

    DoSomethingMethod(names, p => p == "Alice");
    

    两者之间的IL没有区别,因为使用lambda表达式的IL更具可读性。再次强调,这些都是c编译器技巧(而不是jit编译器技巧),因此对性能没有影响。正如我不觉得我们过度使用匿名方法一样,我也不觉得我们过度使用lambda表达式来表示匿名方法。当然,同样的逻辑也适用于重复的代码:不要使用lambdas,使用常规委托。还有其他一些限制会引导您返回匿名方法或纯委托,如out或ref参数传递。

    lambda表达式的另一个优点是,完全相同的语法不需要表示匿名方法。lambda表达式也可以表示…你猜,表情。举个例子:

    public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression<Func<string, bool>> myExpression)
    {
        Console.WriteLine("Lambda used to represent an expression");
        BinaryExpression bExpr = myExpression.Body as BinaryExpression;
        if (bExpr == null)
            return;
        Console.WriteLine("It is a binary expression");
        Console.WriteLine("The node type is {0}", bExpr.NodeType.ToString());
        Console.WriteLine("The left side is {0}", bExpr.Left.NodeType.ToString());
        Console.WriteLine("The right side is {0}", bExpr.Right.NodeType.ToString());
        if (bExpr.Right.NodeType == ExpressionType.Constant)
        {
            ConstantExpression right = (ConstantExpression)bExpr.Right;
            Console.WriteLine("The value of the right side is {0}", right.Value.ToString());
        }
     }
    

    请注意稍微不同的签名。第二个参数接收表达式而不是委托。调用此方法的方法是:

    DoSomethingExpression(names, p => p == "Alice");
    

    这与使用lambda创建匿名方法时所做的调用完全相同。这里的区别在于,我们不是创建匿名方法,而是创建表达式树。正是由于这些表达式树,我们才可以将lambda表达式翻译成SQL,例如LINQ 2 SQL所做的,而不是在引擎中为每个子句执行内容,比如在哪里,选择,好的方面是无论是创建匿名方法还是发送表达式,调用语法都是相同的。

        2
  •  25
  •   Jerry Nixon    14 年前

    我的答案不会受欢迎。

    我相信兰达的99%总是更好的选择,原因有三。

    首先,假设你的开发人员是聪明的绝对没有错。其他的答案都有一个潜在的前提,那就是除了你之外的每个开发人员都很愚蠢。不是这样。

    其次,lamdas(等人)是一种现代语法——明天它们将比今天更为常见。您的项目代码应该来自当前和新兴的约定。

    第三,用“传统的方式”编写代码对你来说可能更容易,但对编译器来说却不容易。这是重要的,传统的方法在编译器被修改时几乎没有机会被改进。依赖于编译器扩展它们的lambdas(et al)可以随着编译器随着时间的推移更好地处理它们而受益。

    总而言之:

    1. 开发人员可以处理它
    2. 每个人都在做
    3. 有未来的潜力

    再说一遍,我知道这不会是一个流行的答案。相信我,“简单就是最好”也是我的口头禅。维护是任何来源的一个重要方面。我明白了。但我认为我们用一些陈词滥调掩盖了现实。

    杰瑞

        3
  •  16
  •   shoosh    17 年前

    代码复制。
    如果你发现自己不止一次地编写同一个匿名函数,那么它不应该是一个。

        4
  •  14
  •   Gabe Timothy Khouri    14 年前

    好吧,当我们讨论委托用法时,lambda和匿名方法应该没有任何区别——它们是相同的,只是语法不同。从运行时的角度来看,命名方法(用作委托)也是相同的。那么,区别就在于使用委托和内联代码之间——即。

    list.ForEach(s=>s.Foo());
    // vs.
    foreach(var s in list) { s.Foo(); }
    

    (我希望后者更快)

    同样,如果你在说什么 其他 与内存对象不同,lambdas是维护类型检查(而不是一直解析字符串)最强大的工具之一。

    当然,有些情况下 foreach 使用代码将比linq版本更快,因为要做的调用将更少,而且调用花费的时间很小,但可以测量。然而,在许多情况下,代码并不是瓶颈,更简单的代码(尤其是分组等)的价值远远超过几纳秒。

    还要注意,在.net 4.0中 additional Expression nodes 对于循环、逗号等,语言不支持它们,但运行时支持。我提这个只是为了完整起见:我当然不是说你应该使用手册 表情 施工地点 前额 会的!

        5
  •  6
  •   jasper johnz    11 年前

    我认为性能差异通常很小(在循环的情况下,很明显,如果你看第二篇文章的结果(顺便说一句,jon skeet有一篇类似的文章 here ))你几乎不应该仅仅因为性能的原因而选择一个解决方案,除非你正在编写一个性能绝对是 这个 首要的非功能性需求,你必须做微观优化。

    什么时候选择什么?我想这取决于情况,也取决于人。举个例子,有些人更喜欢list.foreach而不是普通的foreach循环。我 亲自 更喜欢后者,因为它通常更可读,但我是谁来反对这一点呢?

        6
  •  4
  •   Dustin Campbell    17 年前

    经验法则:

    1. 写代码要自然易读。
    2. 避免代码重复(lambda表达式可能需要额外的努力)。
    3. 只有在出现问题时才进行优化,并且只有使用数据来备份问题的实际情况。
        7
  •  4
  •   MichaelGG    17 年前

    任何时候lambda只需将其参数直接传递给另一个函数。不要为函数应用程序创建lambda。

    例子:

    var coll = new ObservableCollection<int>();
    myInts.ForEach(x => coll.Add(x))
    

    更好的是:

    var coll = new ObservableCollection<int>();
    myInts.ForEach(coll.Add)
    

    主要的例外是C_的类型推断由于任何原因失败(而且很多时候都是这样)。

        8
  •  2
  •   Daniel Earwicker    17 年前

    如果你需要递归,不要使用lambdas, or you'll end up getting very distracted !

        9
  •  2
  •   Community Mohan Dere    9 年前

    lambda表达式很酷。 过岁 delegate 句法 它们有一些优点,例如,它们可以转换为匿名函数或表达式树,从声明中推断出参数类型,它们更干净、更简洁。在需要匿名函数的情况下,我看不到使用lambda表达式的实际值。早期样式的一个不太大的优点是,如果不使用参数声明,则可以省略。喜欢

    Action<int> a = delegate { }; //takes one argument, but no argument specified
    

    当您必须声明一个空委托而该委托什么也不做时,这非常有用,但它不是 坚强的 足够的理由不使用lambdas。

    lambdas允许您编写快速的匿名方法。这使得lambdas在匿名方法变得毫无意义的地方变得毫无意义。 过度命名的方法 匿名方法可能是不利的(不是lambda表达式本身,但是从现在开始,lambdas广泛地表示匿名方法,这是相关的):

    1. 因为它往往会导致逻辑重复(通常是这样,重用是困难的)

    2. 当没有必要写信给某人时,例如:

      //this is unnecessary 
      Func<string, int> f = x => int.Parse(x);
      
      //this is enough
      Func<string, int> f = int.Parse;
      
    3. 因为编写匿名迭代器块是不可能的。

      Func<IEnumerable<int>> f = () => { yield return 0; }; //impossible
      
    4. 因为递归lambda需要一行奇怪的代码,比如

      Func<int, int> f = null;
      f = x => (x <= 1) ? 1 : x * f(x - 1);
      
    5. 好吧,既然反思有点混乱,那就没什么意义了,不是吗?

    除了第三点,其余的都不是 坚强的 原因 不使用 兰姆达斯

    也看到这个 thread 关于什么是不利的 Func/Action 委托,因为它们通常与lambda表达式一起使用。

    推荐文章