Являются ли эти примеры закрытием С#?
Я все еще не совсем понимаю, что такое закрытие, поэтому я разместил эти два примера, и я хочу знать, являются ли эти примеры закрытыми или нет?
Пример 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; }
...
}