2015-12-14 12 views
5

などの変数をキャプチャし、それらを読み違いのは、我々は、このクラスを持っているとしましょう:クロージャ - 引数

// 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と同じことが起こりますか? (引数は参照型であり、この例のように値の型ではないと考えてください)

答えて

1

変数abを渡すと、あなたはそれだけです。 14の値がそれぞれ渡されます。ただし、ラムダ式のコンテキスト(またはスコープ)内でabを参照すると、値は「取得されます」。ラムダ式の範囲内にある変数abは、範囲外のオリジナルへの参照として扱われます。つまり、ラムダの範囲内で変更された場合、オリジナルも同様です。 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には実際に小さな違いがあります。どちらか一方を避ける価値のあるパフォーマンスの影響はないと思います。私は通常、読みやすさのためにラムダ式の使用を好むでしょう。

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

関連する問題