I'm trying to create a MethodCallExpression to a method, that takes a parameter by reference (and may modify this parameter). This Expression is part of a ExpressionTree, that gets compiled to a delegate later.
For non-readonly fields all works as expected, but when I pass in a readonly field, the compiler somehow passes the field by value and changing the parameter doesn't affect the readonly field. The object from which the readonly field comes can be a struct or object.
How can I trick the compiler to pass the readonly field as an actual reference?
I know, that it supposed to be readonly, but with reflection, you also can modify the field. (even with structs: FieldInfo.SetValueDirect(__makeref(...), value)
)
Example Code:
internal class Program
{
private struct Foo
{
private readonly int MyInt;
public Foo(int myInt)
{
MyInt = myInt;
}
}
public static void IncrementInt(ref int i)
{
i++;
}
private delegate void RefAction<T>(ref T parameter);
private static void Main(string[] args)
{
var field = typeof(Foo).GetField("MyInt", BindingFlags.NonPublic | BindingFlags.Instance);
var method = typeof(Program).GetMethod(nameof(IncrementInt));
var parameter = Expression.Parameter(typeof(Foo).MakeByRefType());
var call = Expression.Call(method, Expression.MakeMemberAccess(parameter, field));
var deleg = Expression.Lambda<RefAction<Foo>>(call, parameter).Compile();
var foo = new Foo(0);
deleg(ref foo);
}
}