我使用 protobuf-net 来序列化/反序列化我的数据。
我有一些相当简单的课程,所以这不是真正的问题。
据我所知,protobuf-net 使用 IL 生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用 IL 写入这样的字段?我可以清楚地看到它运作良好,但我不知道为什么......
我试图在代码中窥探它,但它有点太复杂了。
我自己生成此类代码的尝试总是会导致 IL 验证器错误。
我使用 protobuf-net 来序列化/反序列化我的数据。
我有一些相当简单的课程,所以这不是真正的问题。
据我所知,protobuf-net 使用 IL 生成来创建序列化/反序列化代码。虽然我的模型中有只读字段,但我想知道如何使用 IL 写入这样的字段?我可以清楚地看到它运作良好,但我不知道为什么......
我试图在代码中窥探它,但它有点太复杂了。
我自己生成此类代码的尝试总是会导致 IL 验证器错误。
实际上,我不能让它失败- 至少在内存中生成时。
让我们从一个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<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
:
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 的示例代码并且......它VerificationException
在 MS .NET 4.0 上抛出。
我已经设法让它工作,但我需要使用参数设置为的DynamicMethod
构造函数,即使在公共字段的情况下也是如此。在这种情况下,参数似乎是多余的。owner
field.DeclaringType
i
SkipVisibility
PS。我相信这个条目应该是评论,但由于缺乏代表,我无法评论其他人的答案。