protobuf-net如何处理只读字段? [英] How does protobuf-net handle readonly fields?

查看:76
本文介绍了protobuf-net如何处理只读字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用protobuf-net对数据进行序列化/反序列化。

I use protobuf-net to serialize/deserialize my data.

我有一些相当简单的类,所以这不是真正的问题。

I have some rather simple classes, so that's no real problem.

据我所知,protobuf-net使用IL生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何用IL写入这样的字段吗?我可以清楚地看到它运行良好,但是我不知道为什么...

As far as I know, protobuf-net uses IL generation to create serialization/deserialization code. While I have readonly fields in my model, I wonder how is it possible to write to such a field with IL? I can plainly see it works well, but I don't know why...

我试图在代码中对其进行监视,但这有点太复杂了。

I've tried to spy it in the code, but it's a bit too complicated.

我自己尝试生成此类代码总是会导致IL验证器错误。

My attempts to generate such code myself always result in IL validator errors.

推荐答案

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

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

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.

这篇关于protobuf-net如何处理只读字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆