2009-10-23 2 views
13

まだクロージャーが何であるかわかりません。この2つの例を掲載しました。これらの例が両方ともクロージャであるかどうかを知りたいですか?これらの例はC#クロージャですか?

例A:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

Action<string> FilterSubFoldersStartA = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith("A"))); 

FilterSubFoldersStartA(@"c:\tempa"); 
FilterSubFoldersStartA(@"c:\tempb"); 

例B:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

string filter = "A"; 

Action<string> FilterSubFoldersStartGen = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith(filter))); 

FilterSubFoldersStartGen(@"c:\tempa"); 

filter = "B"; 

FilterSubFoldersStartGen(@"c:\tempb"); 

答えて

6

いや、クロージャがそれている環境からいくつかの変数を "節約" という機能以外の何ものでもありませんが定義される。したがって、両方の例で定義されたアクションは、ローカル変数が有効範​​囲外になった後でも関数によって参照できるsubFoldersという名前のリストを保存します。 2番目の例のfilter変数も、定義された関数によって保存されます。

here

9

あなたの第二の例は、クロージャを使用するより正確な定義は、(技術的に、あなたは、コンパイラは両方のケースで閉鎖を計算することを言うことができる、しかし、あなたは最初のケースでそれを使用しません)。

クロージャは、単に「この関数で表示可能なすべての変数」です。それ以上のものはありません。そして明らかに、どちらの場合も、これらの変数は存在し、コンパイラによって決定されます。

しかし、私たちが "クロージャを使う"ことについて話すとき、ラムダ式は宣言された場所で見えるすべてのローカル変数を使うことができるということです。彼らはすべて閉鎖の一部です。

あなたのケースでは、dは単なるラムダ関数のパラメータです。最初のケースではこれがすべて使用されているので、実際にはクロージャを利用していません。

filterはラムダ式で定義されていませんが、パラメータなどではありません。これはラムダが宣言された場所で見えるようになるローカル変数です。それはラムダのクロージャの一部です。これはラムダの本体でそれを参照できるようにします。

編集
コメントで指摘したように、私はあまりにも密接にあなたのコードを読んでいません。私は各例で2番目のラムダ式に気づいただけです。最初のラムダはクロージャを使用します(どちらの場合もsubFoldersで終了します)。

+2

最初の例は 'subFolders'で終了するので、クロージャでもあります。 –

+0

ああ、私は最初のラムダに気付かなかった。私はちょうど 'd => ... 'を見た。あなたが正しい。最初のファイルは 'subFolders'でクローズされ、2番目のファイルは' filter'でクローズされます。 – jalf

0

両方の例でクロージャがあります。 "A"では、匿名メソッドはローカル変数subFoldersを取得します。 "B"では、匿名メソッドはローカル変数subFoldersとfilterを取得します。また、hereを見てください。

P.S. subFolders変数を使用しているため、実際には "A"でクロージャーを使用しています。

0

ここでは、JavaScriptに慣れている場合にはもう少しよく見えるかもしれないhttp://www.agileatwork.com/a-proper-closure-in-csharp/の例を示します。変数はtaxのまわりに作成されるので、計算は1回だけ行われます。それは目には厳密には簡単ではありませんが、あなたはC#でこのタイプのことをすることができることは素晴らしいことです。

public class Order 
{ 
    public Order(ITaxCalculator taxCalculator) 
    { 
     CalculateTax = new Func<Func<decimal>>(() => 
     { 
      decimal? tax = null; 
      return() => 
      { 
       if (!tax.HasValue) 
       { 
        tax = taxCalculator.Calculate(this); 
       } 
       return tax.Value; 
      }; 
     })(); 
    } 

    public Func<decimal> CalculateTax { get; set; } 

    ... 
} 
関連する問題