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

我使用protobuf-net来序列化/反序列化我的数据。

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

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

我试图在代码中窥探它,但它有点太复杂了。

我自己尝试生成此类代码总是会导致ILvalidation程序错误。

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

让我们简单地开始,使用public readonly字段(因此我们不会破坏任何可访问性规则); 我的第一次尝试如下,它工作正常:

 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 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)method.CreateDelegate(typeof(Action)); } } 

它变得有趣的唯一时间是该字段是private

 private readonly int i; 

上面的代码然后给出了如此模糊:

操作可能会破坏运行时的稳定性。

但是我们通过假装该方法在字段的声明类型中来解决这个问题:

 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工具(预生成程序集)无法处理与内存中元编程代码完全相同的场景。

由于我对这个讨论很感兴趣,我尝试了Marc Gravell的示例代码,并且它在MS .NET 4.0上抛出了VerificationException

我已设法使其工作,但我需要使用DynamicMethod构造函数,并将owner参数设置为field.DeclaringType即使在public i字段的情况下也是如此。 在这种情况下, SkipVisibility参数似乎是多余的。

PS。 我相信这个条目应该是一个评论,但由于缺乏代表,我无法评论其他人的答案。