Что такого особенного в замыканиях? - PullRequest
12 голосов
/ 17 апреля 2009

Я читал эту статью о замыканиях , в которой говорится:

  • "все сантехника автоматическая"
  • компилятор "создает класс-оболочку" и "продлевает жизнь переменных"
  • «Вы можете использовать локальные переменные, не беспокоясь»
  • компилятор .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;
        }
    }
}

Ответ

Итак, ответ на этот вопрос - прочитать статью Джона Скита о замыканиях , на которую указал Марк. Эта статья не только показывает эволюцию, приводящую к лямбда-выражениям в C #, но также показывает, как обрабатываются замыкания в Java, что отлично подходит для этой темы.

Ответы [ 2 ]

20 голосов
/ 17 апреля 2009

Ваш пример не ясен, и (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 # делает за кулисами. Обратите внимание, что когда задействованы дополнительные области, мы начинаем объединять различные классы захвата (т.е. внутренние области имеют ссылку на класс захвата внешних областей). Довольно сложный.

У Джона Скита есть хорошая статья по этому вопросу здесь , и больше в его книге .

0 голосов
/ 17 апреля 2009

Закрытие является функциональностью компилятора. Вы этого не видите, это просто заставляет код, который вы пишете, работать.

Без этого вызов AddToIt (3) не будет выполнен, поскольку базовая лямда использует локальную переменную a = 27 в области действия AddToItClusure (). Эта переменная не существует, когда вызывается AddToIt.

Но из-за Closure, механизма, используемого компилятором, код работает, и вам не нужно об этом заботиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...