Imagine we have a mutable struct (yes, don\'t start):
public struct MutableStruct
{
public int Foo { get; set; }
public override string
I've posted a solution using Expression Trees for setting fields in another thread. It's trivial to change the code to use properties instead:
Well, that was fun.
Using
Actually, it's mostly Unbox (see history for version that works with Ldflda and Stind_*).Ldflda and Stind_* seems to work.
Here's what I hacked together in LinqPad to prove it out.
public struct MutableStruct
{
public int Foo { get; set; }
public override string ToString()
{
return Foo.ToString();
}
}
void Main()
{
var foo = typeof(MutableStruct).GetProperty("Foo");
var setFoo = foo.SetMethod;
var dynMtd = new DynamicMethod("Evil", typeof(void), new [] { typeof(object), typeof(int) });
var il = dynMtd.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // object
il.Emit(OpCodes.Unbox, typeof(MutableStruct)); // MutableStruct&
il.Emit(OpCodes.Ldarg_1); // MutableStruct& int
il.Emit(OpCodes.Call, setFoo); // --empty--
il.Emit(OpCodes.Ret); // --empty--
var del = (Action<object, int>)dynMtd.CreateDelegate(typeof(Action<object, int>));
var mut = new MutableStruct { Foo = 123 };
var boxed= (object)mut;
del(boxed, 456);
var unboxed = (MutableStruct)boxed;
// unboxed.Foo = 456, mut.Foo = 123
}
Here you go:
Just use unsafe :)
static void Main(string[] args)
{
object foo = new MutableStruct {Foo = 123};
Console.WriteLine(foo);
Bar(foo);
Console.WriteLine(foo);
}
static unsafe void Bar(object foo)
{
GCHandle h = GCHandle.Alloc(foo, GCHandleType.Pinned);
MutableStruct* fp = (MutableStruct*)(void*) h.AddrOfPinnedObject();
fp->Foo = 789;
}
IL implementation is left as an exercise to the reader.
Update:
Based on the Kevin's answer, here is a minimal working example:
ldarg.0
unbox MutableStruct
ldarg.1
call instance void MutableStruct::set_Foo(int32)
ret
Even without unsafe code, pure C#:
using System;
internal interface I {
void Increment();
}
struct S : I {
public readonly int Value;
public S(int value) { Value = value; }
public void Increment() {
this = new S(Value + 1); // pure evil :O
}
public override string ToString() {
return Value.ToString();
}
}
class Program {
static void Main() {
object s = new S(123);
((I) s).Increment();
Console.WriteLine(s); // prints 124
}
}
In C#, this reference inside value types instance methods actually is ref-parameter (or out-parameter in value type constructor, and that is why this can't be captured into closures, just like ref/out parameters in any methods) and can be modified.
When struct instance method is invoked on unboxed value, this assignment will effectively replace value at the call site. When instance method is invoked on boxed instance (via virtual call or interface call like in the example above), ref-parameter is pointed to the value inside the box object, so it is possible to modify boxed value.
You can do this even easier. Try this under .NET 4.5 where we have dynamic.
struct Test
{
public Int32 Number { get; set; }
public override string ToString()
{
return this.Number.ToString();
}
}
class Program
{
static void Main( string[] args )
{
Object test = new Test();
dynamic proxy = test;
proxy.Number = 1;
Console.WriteLine( test );
Console.ReadLine();
}
}
I know it's not reflection but still fun though.