Вот полное решение:
// Credits to digEmAll for the following code
public delegate void Setter<T>(T newValue);
public delegate T Getter<T>();
public class MagicPointer<T>
{
private Getter<T> getter;
private Setter<T> setter;
public T Value
{
get { return getter(); }
set { setter(value); }
}
public MagicPointer(Getter<T> getter, Setter<T> setter)
{
this.getter = getter;
this.setter = setter;
}
}
// Code starting from here is mine
public static class MagicUtilClass
{
public static MagicPointer<T> LinkVariable<T>(Expression<Func<T>> expression)
{
var memberExpr = expression.Body as MemberExpression;
if (memberExpr == null)
throw new InvalidOperationException("The body of the expression is expected to be a member-access expression.");
var field = memberExpr.Member as FieldInfo;
if (field == null)
throw new InvalidOperationException("The body of the expression is expected to be a member-access expression that accesses a field.");
var constant = memberExpr.Expression as ConstantExpression;
if (constant == null)
throw new InvalidOperationException("The body of the expression is expected to be a member-access expression that accesses a field on a constant expression.");
return new MagicPointer<T>(() => (T) field.GetValue(constant.Value),
x => field.SetValue(constant.Value, x));
}
}
Использование:
int x = 47;
var magic = MagicUtilClass.LinkVariable(() => x);
magic.Value = 48;
Console.WriteLine(x); // Outputs 48
Чтобы понять, почему это решение работает, вам нужно знать, что компилятор довольно сильно преобразует ваш код всякий раз, когда вы используете переменную внутри лямбда-выражения (независимо от того, становится ли это лямбда-выражение делегатом или выражением дерево). На самом деле он генерирует новый класс, содержащий поле. Переменная x удаляется и заменяется этим полем. Пример использования будет выглядеть примерно так:
CompilerGeneratedClass1 locals = new CompilerGeneratedClass1();
locals.x = 47;
var magic = MagicUtilClass.LinkVariable(() => locals.x);
// etc.
«Поле», которое извлекает код, является полем, содержащим x , а «константа», которую он извлекает, является экземпляром locals .