2015-07-25 6 views
6

Я понимаю, что захват переменных выполняется компилятором, а не классами в самой платформе .NET. Однако, когда DLR была введена, некоторые из этих работ, несомненно, должны были быть выполнены в рамках, чтобы отложить ее до среды выполнения.Каков код, который создает захваченные переменные/замыкания?

Для получения, например, в части коды, приведенной ниже:

dynamic d = ... 

Func<int, bool> func = n => n > d; 

Разрешение типа переменной d и его подтверждение того, что она представляет собой целое число должно быть должны быть сделано во время выполнения. А так как d является переменной в методе хранения лямбда, он будет захвачен в закрытие. Эта часть, безусловно, будет выполнена во время выполнения.

Следовательно, я полагаю, что должна быть какая-то часть сборок DLR (System.Core.dll в основном) это делает эта часть.

Я искал, и я мог найти некоторые классы, которые выглядят подозрительно предосудительными для такого рода задач. В частности, ExpressionQuoter (несмотря на внешний вид этого класса, этот класс не цитирует лямбда-выражения, как метод Expression.Quote), HoistedLocals и VariableBinder.

Я думал, что приглашу кого-то, кто знает, что лучше ответить на это.

Каким классом или частью .NET Framework являются локаторы, которые содержат методы lambdas (или анонимные методы) в те отдельные классы, у которых есть статические переменные, представляющие их?

ответ

0

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

d не нужно захватывать, потому что лямбда не использует его. Если компилятор C# решит его захватить (что запрещено в соответствии с правилом as-if), это никак не будет доступно.

Я считаю, что func(d) выполнен как любой вызов метода с динамическим аргументом.

Давайте посмотрим на:

dynamic d = ...; //maybe "1" 

Func<bool> func = (() => d == "1234"); 

Я думаю, что это больше в духе того, что вы хотите знать (Update: На самом деле вы просто редактировал вопрос, чтобы иметь этот шаблон). Лямбда зависит от d, чего раньше не было.

Здесь d улавливается в созданном классе закрытий как полевого типа object. dynamic всегда скомпилирован как object (потенциально с настраиваемым атрибутом на нем). Затем тело лямбда-кода переходит к использованию стандартных динамических операций.

Поскольку все ссылки переменных в C# статически привязаны к определенной переменной, никогда не требуется захватывать динамическое число полей или что-то в этом роде. Поля для захвата статически известны.

+0

Простите за эту опечатку раньше. Я исправил свой фрагмент кода после того, как вы впервые прокомментировали вопрос. –

+0

Не беспокойтесь. Отвечает ли это на вопрос? – usr

+0

Да, сэр. Оно делает. Я забыл, что динамика является заполнитель для объекта в отношении компилятора. Спасибо. –

2

Какой класс или часть платформы .NET превращает местных жителей, которые в , содержащие методы лямбды (или анонимные методы) в этих отдельные классы, которые имеют статические переменные, представляющие их?

Нет, это компилятор, который выполняет эту работу.

Как передать значения переменных в отдельный метод ? Единственный способ сделать это - определить новый вспомогательный класс, который также определяет поле для каждого значения, которое вы хотите передать в код обратного вызова . Кроме того, код обратного вызова должен быть определен как метод экземпляра в этом вспомогательном классе. Затем, UsingLocalVariablesInTheCallbackCodemethod должен был бы построить экземпляр вспомогательного класса, инициализировать поля из значений в его локальными переменными, а затем построить объект делегирования, связанный с методом вспомогательного объекта/экземпляра.

Это очень утомительным и подверженным ошибкам работы, и, конечно, C# компилятор делает все это для вас автоматически

Из книги CLR Via C#

С вашим кодом, там - это генерируемый класс, который выглядит так:

class SomeClass 
{ 
    public dynamic d; 
    public bool yourCallBack(int n) 
    { 
     return n > d; 
    } 
} 

и ваш код скомпилирован в нечто вроде:

dynamic d = ... 
SomeClass class1= new SomeClass(); 
class1.d = d; 
Func<int, bool> func = class1.yourCallBack; 

Существует также примечание относительно времени жизни захваченных переменных:

Когда лямбда-выражение заставляет компилятор генерировать класс с параметром/локальные переменные превращена в полях, время жизни объекты, к которым относятся переменные, удлиняются. Обычно параметр /локальная переменная выходит за пределы области применения при последнем использовании переменной внутри метода. Однако превращение переменной в поле приводит к тому, что поле сохраняет объект, к которому он относится, к живому для времени жизни объекта, содержащего поле. Это не большая сделка в большинстве приложений, но это то, о чем вы должны знать .

+0

Я считаю, что Джеффри говорит о том, как компилятор генерирует одно и то же. До C# 3.0 компилятор был единственным местом, в котором было это преобразование.С C# 4 я считаю, что у них есть причина переместить много того, что делает компилятор в DLR, чтобы поддерживать привязку времени выполнения операций к динамическому типу. –

+1

Спасибо за все это. Тем не менее, это действительно не соответствует моему вопросу. Вы объясняете, как работают замыкания, и это не мой вопрос. –