Являются ли эти примеры C # замыканиями? - PullRequest
13 голосов
/ 23 октября 2009

Я все еще не совсем понимаю, что такое замыкание , поэтому я опубликовал эти два примера, и я хочу знать, являются ли эти примеры замыканиями или нет?

Пример 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");

Ответы [ 4 ]

9 голосов
/ 23 октября 2009

Ваш второй пример использует замыкания (технически можно сказать, что компилятор вычисляет замыкание в обоих случаях, но вы не используете его в первом случае).

Закрытие - это просто "все переменные, видимые этой функции". Ни больше ни меньше. И очевидно, что в обоих случаях эти переменные существуют и определяются компилятором.

Но что мы обычно имеем в виду, когда говорим об «использовании замыканий», так это о том, что лямбда-выражения могут использовать все локальные переменные, видимые в месте, которое они объявили. Они все часть его закрытия.

В вашем случае d - это просто параметр лямбда-функции, и, поскольку это все, что вы используете в первом случае, вы на самом деле не пользуетесь замыканиями.

Во втором случае filter не определено в лямбда-выражении, это не параметр или что-то еще. Это локальная переменная, которая, как оказалось, видна в том месте, где объявлена ​​лямбда. Так что это часть лямбда-замыкания, которая позволяет ссылаться на него в теле лямбды.

Редактировать
Как указано в комментариях, я не слишком внимательно читал ваш код. Я заметил только второе лямбда-выражение в каждом примере. Первая лямбда использует закрытие (в обоих случаях она закрывается свыше subFolders)

6 голосов
/ 23 октября 2009

Да, замыкание - это не что иное, как функция, которая «сохраняет» некоторые переменные из среды, в которой она определена. Таким образом, в обоих ваших примерах определенное действие сохраняет список с именем subFolders, на который могут ссылаться функции даже после того, как локальная переменная выходит из области видимости. Переменная filter во втором примере также сохраняется определенной функцией.

Более точное определение здесь

0 голосов
/ 19 декабря 2010

Вот пример из http://www.agileatwork.com/a-proper-closure-in-csharp/ того, что может показаться немного более знакомым, если вы знакомы с JavaScript. Вокруг переменной tax создается замыкание, поэтому вычисление выполняется только один раз. Это не совсем легко для глаз, но это здорово, что вы можете делать такие вещи в 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; }

    ...
}
0 голосов
/ 23 октября 2009

Оба примера имеют замыкания. В «А» анонимный метод перехватывает локальные переменные subFolders. В "B" анонимный метод захватывает локальные переменные subFolders и filter. Также посмотрите здесь .

P.S. Также обратите внимание, что вы на самом деле используете замыкание в "A", потому что используете переменную subFolders.

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