Что такое закрытие ? У нас они есть в .NET?
Если они существуют в .NET, не могли бы вы предоставить фрагмент кода (желательно в C #), объясняющий это?
У меня есть статья на эту тему . (Есть много примеров.)
По сути, замыкание - это блок кода, который может быть выполнен позднее, но который поддерживает среду, в которой он был впервые создан, то есть он все еще может использовать локальные переменные и т. Д. Метода, который его создал, даже после этого. Метод завершил выполнение.
Общая особенность замыканий реализована в C # анонимными методами и лямбда-выражениями.
Вот пример использования анонимного метода:
using System;
class Test
{
static void Main()
{
Action action = CreateAction();
action();
action();
}
static Action CreateAction()
{
int counter = 0;
return delegate
{
// Yes, it could be done in one statement;
// but it is clearer like this.
counter++;
Console.WriteLine("counter={0}", counter);
};
}
}
Вывод:
counter=1
counter=2
Здесь мы видим, что действие, возвращаемое CreateAction, все еще имеет доступ к переменной counter и может действительно увеличивать его, даже если сам CreateAction завершил работу.
counter
доступно для увеличения - компилятор генерирует класс, который содержитcounter
поле, и любой код, ссылающийся на него, вcounter
конечном итоге проходит через экземпляр этого класса.Если вам интересно посмотреть, как C # реализует Closure, прочитайте «Я знаю ответ (его 42) блог»
Компилятор генерирует класс в фоновом режиме для инкапсуляции аномального метода и переменной j
для функции:
Превращая это в:
источник
Замыкания - это функциональные значения, которые держатся за значения переменных из их первоначальной области видимости. C # может использовать их в виде анонимных делегатов.
Для очень простого примера возьмем этот код C #:
В конце этого бара будет установлено значение 4, и делегат myClosure может быть передан для использования в другом месте в программе.
Замыкания могут использоваться для многих полезных вещей, таких как отложенное выполнение или для упрощения интерфейсов - LINQ в основном построен с использованием замыканий. Наиболее непосредственный способ, которым это пригодится большинству разработчиков, - это добавление обработчиков событий к динамически создаваемым элементам управления - вы можете использовать замыкания для добавления поведения при создании экземпляра элемента управления вместо хранения данных в другом месте.
источник
Закрытие - это анонимная функция, передаваемая вне функции, в которой она создается. Он поддерживает любые переменные из функции, в которой он создан, который он использует.
источник
Вот надуманный пример для C #, который я создал из похожего кода в JavaScript:
Итак, вот код, который показывает, как использовать приведенный выше код ...
Надеюсь, что это несколько полезно.
источник
Замыкания - это фрагменты кода, которые ссылаются на переменную вне себя (из-под них в стеке), которые могут быть вызваны или выполнены позже (например, когда определено событие или делегат и могут быть вызваны в какой-то неопределенный момент времени в будущем). ) ... Поскольку внешняя переменная, на которую ссылается кусок кода, может выйти из области видимости (и в противном случае она была бы потеряна), тот факт, что на нее ссылается кусок кода (называемый замыканием), сообщает среде выполнения "hold" msgstr "эта переменная в области видимости, пока она больше не нужна закрывающему фрагменту кода ...
источник
По сути, замыкание - это блок кода, который вы можете передать в качестве аргумента функции. C # поддерживает замыкания в форме анонимных делегатов.
Вот простой пример:
метод List.Find может принимать и выполнять фрагмент кода (замыкание), чтобы найти элемент списка.
Используя синтаксис C # 3.0, мы можем написать это так:
источник
Закрытие - это когда функция определяется внутри другой функции (или метода) и использует переменные из родительского метода . Такое использование переменных, которые находятся в методе и заключены в определенную в нем функцию, называется замыканием.
У Марка Симанна есть несколько интересных примеров замыканий в своем блоге, где он проводит параллель между ООП и функциональным программированием.
И чтобы это было более подробно
источник
Я тоже пытался это понять, ниже приведены фрагменты кода для того же кода в Javascript и C #, показывающие замыкание.
JavaScript:
C #:
JavaScript:
C #:
источник
Просто неожиданно, простой и более понятный ответ из слов C # 7.0.
Предварительное условие, которое вы должны знать : лямбда-выражение может ссылаться на локальные переменные и параметры метода, в котором оно определено (внешние переменные).
Реальная часть : Внешние переменные, на которые ссылается лямбда-выражение, называются захваченными переменными. Лямбда-выражение, которое захватывает переменные, называется замыканием.
Последнее замечание : зафиксированные переменные оцениваются, когда делегат действительно вызывается, а не когда переменные были захвачены:
источник
Если вы напишите встроенный анонимный метод (C # 2) или (предпочтительно) лямбда-выражение (C # 3 +), фактический метод все еще создается. Если этот код использует локальную переменную внешней области видимости - вам все равно нужно как-то передать эту переменную в метод.
например, возьмем это предложение Linq Where (это простой метод расширения, который передает лямбда-выражение):
если вы хотите использовать i в этом лямбда-выражении, вы должны передать его созданному методу.
Итак, первый вопрос, который возникает: должен ли он передаваться по значению или по ссылке?
Передача по ссылке является (я думаю) более предпочтительной, поскольку вы получаете доступ для чтения / записи к этой переменной (и это то, что делает C #; я полагаю, что команда в Microsoft взвесила все за и против и пошла по ссылке; согласно словам Джона Скита статья , Java пошла с побочной стоимостью).
Но тогда возникает другой вопрос: где выделить это я?
Должен ли он на самом деле / естественно размещаться в стеке? Что ж, если вы разместите его в стеке и передадите его по ссылке, могут быть ситуации, когда он переживает свой собственный кадр стека. Возьмите этот пример:
Лямбда-выражение (в предложении Where) снова создает метод, который ссылается на i. Если i размещен в стеке Outlive, то к тому времени, когда вы перечислите whereItems, i, использованный в сгенерированном методе, будет указывать на i из Outlive, то есть на место в стеке, которое больше не доступно.
Хорошо, тогда нам нужно это в куче.
Итак, что компилятор C # делает для поддержки этого встроенного анонимного / лямбда-выражения, использует то, что называется « Closures »: он создает класс в куче с именем ( довольно плохо ) DisplayClass, который имеет поле, содержащее i, и функцию, которая фактически использует Это.
Что-то, что было бы эквивалентно этому (вы можете увидеть IL, сгенерированный с использованием ILSpy или ILDASM):
Он создает этот класс в локальной области видимости и заменяет любой код, относящийся к i или лямбда-выражению, этим экземпляром замыкания. Итак, всякий раз, когда вы используете i в своем коде «локальной области», где я был определен, вы фактически используете это поле экземпляра DisplayClass.
Так что, если бы я изменил «local» i в методе main, он фактически изменит _DisplayClass.i;
т.е.
он выведет 12, так как «i = 10» переходит в это поле dispalyclass и изменяет его непосредственно перед вторым перечислением.
Хороший источник по этой теме - модуль Барт де Смет Pluralsight (требует регистрации) (также игнорируйте его ошибочное использование термина «Подъем» - что (я думаю) он имеет в виду, что локальная переменная (то есть i) изменена для ссылки в новое поле DisplayClass).
В других новостях, кажется, есть некоторое заблуждение, что «Замыкания» связаны с циклами - как я понимаю, «Замыкания» - это НЕ концепция, связанная с циклами , а скорее с анонимными методами / лямбда-выражениями, использующими локальные переменные области видимости - хотя некоторые хитрости вопросы используют циклы, чтобы продемонстрировать это.
источник
Замыкание - это функция, определенная внутри функции, которая может обращаться к ее локальным переменным, а также к ее родителю.
так что функция внутри метода поиска.
может получить доступ к переменным внутри своей области видимости t и имени переменной, которая находится в родительской области видимости. Даже если он выполняется методом find как делегат, из другой области видимости все вместе.
источник