Доступ к переменным закрытия в делегате func c # - PullRequest
0 голосов
/ 28 февраля 2019
public Func<string, string> getdel()
{
    int i = 1;
    int j = 1;
    return s => s.ToUpper() + (i++);
}

public Func<string, string> aa = getdel()
aa("Test");

Значение переменной закрытия возвращается в свойстве Target делегата. Как я могу получить доступ к значению переменной закрытия? Примерно так:

((appropriatecast)(aa.Target)).i

При достижении точки останова в делегате я вижу значениеиз i, но в коде это appropriatecast является <> c__DisplayClass2_0, сгенерированным компилятором (проверено в IL Disassembler).

1 Ответ

0 голосов
/ 28 февраля 2019

Вы не можете просто привести замыкание к его конкретному типу, так как имя заранее не известно и (вполне преднамеренно) является недопустимым именем в C #.

Вы можете попытаться получить доступ к его полям либо с помощьюdynamic:

dynamic target = aa.Target;
int value = target.i;

или с отражением:

var closureType = aa.Target.GetType();
var field = closureType.GetField("i");
var value = (int)field.GetValue(aa.Target);

Однако я настоятельно рекомендую не полагаться на это, поскольку нет никаких гарантий относительно способа, которым компилятор решит сгенерироватьзакрытие и назовите переменные.Различные версии компилятора или, казалось бы, несвязанные модификации лямбды могут привести к очень разным результатам, что приведет к поломке этого кода.

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

public class Foo
{
    public int i;    
    public string Bar(string s) => s.ToUpper() + (i++);
}
var foo = new Foo();
Func<string, string> aa = foo.Bar;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...