12

私は彼らが言う閉鎖についてこの記事を読んでいます:

  • 「配管はすべて自動」
  • コンパイラは「ラッパークラスを作成」し、「変数の寿命を延ばします」
  • 「安心してローカル変数を使える」
  • .NET コンパイラが配管などを処理します。

だから私は彼らのコードに基づいて例を作った.

または、この「ローカル変数のラッピング」によって解決された、クロージャーを特別/興味深い/便利にする問題は何ですか?

using System;
namespace TestingLambda2872
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int> AddToIt = AddToItClosure();

            Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30
            Console.ReadLine();
        }

        public static Func<int, int> AddToItClosure()
        {
            int a = 27;
            Func<int, int> func = s => s + a;
            return func;
        }
    }
}

答え

したがって、これに対する答えは、Marc が指摘したクロージャに関する Jon Skeet の記事を読むことです。この記事は、C# のラムダ式に至るまでの進化を示すだけでなく、Java でクロージャがどのように処理されるかについても示しており、このトピックの優れた読み物です。

4

2 に答える 2

20

あなたの例は明確ではなく、(IMO)典型的なキャプチャの使用法を示していません(キャプチャさaれるのは常に3であるため、あまり興味深いものではありません)。

次の教科書の例 (述語) を考えてみましょう。

List<Person> people = ...
string nameToFind = ...
Person found = people.Find(person => person.Name == nameToFind);

クロージャーなしで試してみてください。私たちが怠惰であっても、もっと多くの作業を行う必要があります。

PersonFinder finder = new PersonFinder();
finder.nameToFind = ...
Person found = people.Find(finder.IsMatch);
...
class PersonFinder {
    public string nameToFind; // a public field to mirror the C# capture
    public bool IsMatch(Person person) {
        return person.Name == nameToFind;
    }
}

キャプチャ アプローチは、さまざまなスコープの多くの変数にさらに拡張されます。多くの複雑さが隠されています。

名前を除いて、上記は C# コンパイラが舞台裏で行うことの概算です。追加のスコープが含まれる場合、異なるキャプチャ クラスの連鎖を開始することに注意してください (つまり、内側のスコープは外側のスコープのキャプチャ クラスへの参照を持ちます)。非常に複雑です。

Jon Skeet はこれについて良い記事を書いてます。

于 2009-04-17T10:18:41.160 に答える
0

クロージャはコンパイラの機能です。あなたはそれを見ません、それはあなたが書いたコードを機能させるだけです.

これがないと、基になるラムダが AddToItClusure() のスコープでローカル変数 a = 27 を使用するため、AddToIt(3) の呼び出しは失敗します。AddToIt が呼び出されたとき、この変数は存在しません。

しかし、コンパイラーによって使用されるメカニズムであるクロージャーのおかげで、コードは機能し、気にする必要はありません。

于 2009-04-17T10:19:41.733 に答える