7

protobuf-net を使用してデータをシリアライズ/デシリアライズします。

私はかなり単純なクラスをいくつか持っているので、それは本当の問題ではありません。

私の知る限り、protobuf-net は IL 生成を使用してシリアライゼーション/デシリアライゼーション コードを作成します。モデルに読み取り専用フィールドがありますが、IL でそのようなフィールドに書き込むにはどうすればよいのでしょうか? うまく機能していることがはっきりとわかりますが、その理由はわかりません...

コードでそれをスパイしようとしましたが、少し複雑すぎます。

そのようなコードを自分で生成しようとすると、常に IL バリデータ エラーが発生します。

4

2 に答える 2

7

実際、少なくともメモリ内で生成するときは、失敗することはありません。

簡単に、フィールドから始めましょう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(アセンブリを事前に生成するための) ツールは、インメモリ メタプログラミング コードとまったく同じ範囲のシナリオを処理できません。

于 2013-06-14T21:27:10.350 に答える
3

私はこの議論に非常に興味があるので、Marc Gravell のサンプル コードを試してみました... VerificationExceptionMS .NET 4.0 でスローされます。

私はそれを機能させることができましたが、パブリックフィールドの場合でも、パラメーターを設定してDynamicMethodコンストラクターを使用する必要がありました。この場合、パラメーターは冗長なようです。ownerfield.DeclaringTypeiSkipVisibility

PS。このエントリはコメントである必要があると思いますが、担当者がいないため、他の人の回答にコメントすることはできません.

于 2013-06-19T13:21:04.853 に答える