【问题标题】:Closures - Difference between capturing variables and reading them as arguments闭包 - 捕获变量和将它们作为参数读取之间的区别
【发布时间】:2016-03-20 09:31:05
【问题描述】:

假设我们有这个类:

// Provides deferred behaviour
public class Command<TResult>
{
     private Func<object[], TResult> _executeFunction;
     private object[] _args;

     public Command(Func<object[], TResult> execution, params object[] arguments)
     {
          _executeFunction = execution;
          _args = arguments;
     }

     public TResult Execute()
     {
          return _executeFunction(_args);
     }
}

这两个匿名函数有什么区别?

int a = 1;
int b = 4;

// a and b are passed in as arguments to the function
Command<int> sum = new Command<int>(args => (int)args[0] + (int)args[1], a, b);

// a and b are captured by the function
Command<int> sum2 = new Command<int>(_ => a + b);

Console.WriteLine(sum.Execute()); //Prints out 5
Console.WriteLine(sum2.Execute()); //Prints out 5

我专门寻找性能差异。

此外,我们知道,如果某个类持有 sum2 的引用,那么 ab 将超出它们定义的范围,如果函数仍然存在,可能永远不会被 GC 收集在任何地方引用。

sum 也会发生同样的情况吗? (考虑到参数是引用类型,而不是本例中的值类型)

【问题讨论】:

    标签: c# .net lambda closures anonymous-function


    【解决方案1】:

    当您传入变量ab 时,您就是这样做的。分别传入14的值。但是,当您在 lambda 表达式的上下文(或范围)内引用 ab 时,这些值将被“捕获”。 lambda 表达式范围内的变量ab 被视为对范围外的原始变量的引用,这意味着如果它们在lambda 的范围内被更改——原始变量也是如此。当编译到 IL 中时,它们驻留在共享实例的类中。

    static void Main()
    {
        int a = 1;
        int b = 4;
    
        // a and b are passed in as arguments to the function
        var sum = new Command<int>(args => (int)args[0] + (int)args[1], a, b);
    
        // a and b are captured by the function
        var sum2 = new Command<int>(_ =>
        {
            var c = a + b;
    
            a++;
            b++;
    
            return c;
        });
    
        Console.WriteLine(sum.Execute()); //Prints out 5
        Console.WriteLine(sum2.Execute()); //Prints out 5
    
        Console.WriteLine("a = " + a); // Prints 2
        Console.WriteLine("b = " + b); // Prints 5
    
        Console.ReadLine();
    }
    

    IL 的差异确实很小,我认为没有任何值得避免的性能影响。出于可读性考虑,我通常更喜欢使用 lambda 表达式。

    A look at some of the IL generated from some C# lambdas.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 2015-09-11
      相关资源
      最近更新 更多