One can store in a read only field of a class using strfld
op code in dynamic method if it has its owner set to that class and JIT checks are turned off. An example is here. This approach, however, failed to work with the class that comes from F#, namely FSharpOption
. Please analyse an example below:
using Microsoft.FSharp.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
#if true
using MyType = Microsoft.FSharp.Core.FSharpOption<string>;
#else
using MyType = System.Tuple<string>;
#endif
namespace ConsoleApplication27
{
class Program
{
static void Main(string[] args)
{
var something = new MyType("test");
var dynMethod = new DynamicMethod("ChangeField", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(void), new [] { typeof(MyType) }, typeof(MyType), true);
var generator = dynMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldstr, "success");
generator.Emit(OpCodes.Stfld, typeof(MyType).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)[0]);
generator.Emit(OpCodes.Ret);
var method = (Action<MyType>) dynMethod.CreateDelegate(typeof(Action<MyType>));
method(something);
Console.WriteLine(typeof(MyType).GetProperties()[0].GetGetMethod().Invoke(something, new object[0]));
}
}
}
First of all, you have to reference FSharp.Core library to run it. Then, by changing #if true
to #if false
you can switch between writing a read only field fo Tuple
and FSharpOption
. For the former it works perfectly even though both have similar structure, that is a single read only field accessible via property. For the latter it causes verification failure. Why is that so?