且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

protobuf-net如何处理只读字段?

更新时间:2023-02-17 13:59:54

实际上,至少在内存中生成时,我无法使它失败

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

让我们开始吧,带有 public readonly 字段(因此我们没有违反任何可访问性规则);我的第一次尝试如下,并且运行良好:

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>));
    }
}

唯一有趣的是,如果字段是 private

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);

通过启用 skipVisibility $ c $,可以完成一些其他内部检查c>:

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

但是,请注意,如果生成独立程序集,并非所有这一切都是可能的。创建实际的dll时,您必须遵守更高的标准。因此, precompiler 工具(用于预生成程序集)无法处理内存元编程代码可以处理的相同场景。

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.