Являются ли эти примеры закрытием С#?

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

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

Ответы

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

Вот пример из http://www.agileatwork.com/a-proper-closure-in-csharp/ того, что может выглядеть немного более знакомым, если вам нравится JavaScript. Закрытие создается вокруг переменной tax, поэтому вычисление выполняется только один раз. Это не совсем просто на глаза, но здорово, что вы можете делать этот тип вещей на С#.

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; }

    ...
}