How does protobuf-net handle readonly fields?

情到浓时终转凉″ 提交于 2019-11-30 20:06:47

Actually, I can't get it to fail - at least, when generating in memory.

Let's start simply, with a public readonly field (so we aren't breaking any accessebility rules); my first attempt is as below, and it works fine:

using System;
using System.Reflection;
using System.Reflection.Emit;
class Foo
{
    public readonly int i;
    public int I { get { return i; } }
    public Foo(int i) { this.i = i; }
}
static class Program
{
    static void Main()
    {
        var setter = CreateWriteAnyInt32Field(typeof(Foo), "i");
        var foo = new Foo(123);
        setter(foo, 42);
        Console.WriteLine(foo.I); // 42;
    }
    static Action<object, int> CreateWriteAnyInt32Field(Type type, string fieldName)
    {
        var field = type.GetField(fieldName,
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        var method = new DynamicMethod("evil", null,
            new[] { typeof(object), typeof(int) });
        var il = method.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Castclass, type);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stfld, field);
        il.Emit(OpCodes.Ret);
        return (Action<object, int>)method.CreateDelegate(typeof(Action<object, int>));
    }
}

The only time it gets interesting is if the field is private:

private readonly int i;

The code above then gives the oh-so-vague:

Operation could destabilize the runtime.

But we get around that by pretending that the method is inside the field's declaring type:

var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(int) }, field.DeclaringType);

Some other internal checks can be done by enabling skipVisibility:

var method = new DynamicMethod("evil", null,
    new[] { typeof(object), typeof(int) }, field.DeclaringType, true);

However, note that not all of this is possible if generating standalone assemblies. You are held to much higher standards when creating actual dlls. For this reason, the precompiler tool (to pre-generate assemblies) cannot handle quite the same range of scenarios that the in-memory meta-programming code can.

As I am quite interested in this discussion, I have tried Marc Gravell's example code and... it throws VerificationException on MS .NET 4.0.

I've managed to make it work but I needed to use DynamicMethod constructor with owner parameter set to field.DeclaringType even in case of public i field. SkipVisibility parameter seems to be redundant in this case.

PS. I believe that this entry should be a comment, but due to the lack of rep I'm unable to comment other's answers.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!