C# protobuf net如何处理只读字段?
我使用protobuf net对数据进行序列化/反序列化 我有一些相当简单的类,所以这不是真正的问题 据我所知,ProtobufNet使用IL生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用IL写入这样的字段?我可以清楚地看到它工作得很好,但我不知道为什么 我试着在代码中发现它,但它有点太复杂了C# protobuf net如何处理只读字段?,c#,protobuf-net,readonly,il,C#,Protobuf Net,Readonly,Il,我使用protobuf net对数据进行序列化/反序列化 我有一些相当简单的类,所以这不是真正的问题 据我所知,ProtobufNet使用IL生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用IL写入这样的字段?我可以清楚地看到它工作得很好,但我不知道为什么 我试着在代码中发现它,但它有点太复杂了 我自己尝试生成这样的代码总是导致IL验证器错误。事实上,我不能让它失败——至少在内存中生成时是这样 让我们简单地从一个公共只读字段开始(这样我们就不会违反任何可访问性规则);
我自己尝试生成这样的代码总是导致IL验证器错误。事实上,我不能让它失败——至少在内存中生成时是这样 让我们简单地从一个
公共只读
字段开始(这样我们就不会违反任何可访问性规则);我的第一次尝试如下,效果很好:
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>));
}
}
上面的代码给出了非常模糊的答案:
操作可能会使运行时不稳定
但我们通过假装该方法在字段的声明类型中来解决这个问题:
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时,您需要遵守更高的标准。因此,
预编译器
工具(用于预生成程序集)无法处理与内存元编程代码相同的场景范围。由于我对本次讨论非常感兴趣,我尝试了Marc Gravell的示例代码并。。。它在MS.NET 4.0上抛出VerificationException
我已经设法使它工作,但我需要使用DynamicMethod
构造函数,将owner
参数设置为字段。DeclaringType
即使在公共I
字段的情况下也是如此<代码>SkipVisibility参数在这种情况下似乎是多余的
另外,我认为这个条目应该是一个注释,但由于缺少代表,我无法对其他人的答案进行注释。我会立即检查它。也许我的问题与只读字段没有严格的关系。有趣的是,我的代码在Mono上运行,而在.NET.Doh上不运行。我未能提供DeclaringType。但现在我想知道,为什么它会起作用?只读字段不应该只能从对象的构造函数写入吗?不管怎样,谢谢你的回答。@PiotrZierhoffer很多东西只在编译器上强制执行,并且完全
PEVerify
。最终,您可以通过反射更改只读
字段,序列化器/物化器通常会完全跳过构造函数,因此如果是这种情况,则无法分配值。应该注意的是,动态方法不允许在完全信任上下文(即普通桌面应用程序)中进行IL验证。因此,如果你能用一种动态的方法做一些事情,那并不能证明它是合法的。如果您的代码正在做一些无法验证的事情(不安全,甚至完全没有意义),JIT无论如何都会很乐意编译它。我将此报告为bug(),但MS拒绝提供验证动态方法的方法。我没有运行Marc的代码,只是对其进行了分析,但这一点似乎是正确的。
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) }, field.DeclaringType, true);