5

リフレクションを使用してすべての安全性をバイパスし、オーバーライドされたメソッドの基本クラスの実装を直接呼び出すことに関する他の 質問は、一般的に、問題のあるコードを再設計するための嘲笑と呼び出しに遭遇しましたが、奇妙ではあるが正当なユースケースに出くわしたと思います:デリゲート連載。他の質問を見たので、コードを再設計し、型システムをバイパスしようとするのをやめるというアドバイスで私を攻撃しないでください-私はシリアライゼーションフォーマッターを書いていますが、それらはすでにコンストラクターを無視するパスを取得しています

残念なことに、v2.0 BCL でさえ、BinaryFormatterこの単純な NUnit テストに失敗します。

[TestFixture]
public class DelegateSerializationTestFixture
{
    [Test]
    public void DelegateSerializationTest()
    {
        var bigKitty = new Lion();
        var kittyNoise = bigKitty.GetKittyNoiseFunc();

        Assert.AreEqual("Meow", kittyNoise());

        var stream = new MemoryStream();
        var formatter = new BinaryFormatter();
        formatter.Serialize(stream, kittyNoise);
        stream.Position = 0;
        formatter = new BinaryFormatter();
        var kittyNoise2 = (Func<string>)formatter.Deserialize(stream);

        Assert.AreEqual("Meow", kittyNoise2()); // returns Grrr
    }
}

[Serializable]
public class Lion : Cat
{
    public override string GetNoise()
    {
        return "Grrr";
    }

    public Func<string> GetKittyNoiseFunc()
    {
        return base.GetNoise;
    }
}

[Serializable]
public class Cat
{
    public virtual string GetNoise()
    {
        return "Meow";
    }
}

それBinaryFormatter自体でこれを正しく行うことができないとしても、私自身の Compact Framework 3.5 バイナリ シリアライゼーションの実装がボールを落としても驚くべきではないと思います。

Compact Framework v3.5 の制限されたリフレクション機能のみを使用してそのようなデリゲートを再構築することが本当に不可能である場合 (そうかもしれません)、少なくともそのようなデリゲートを検出して、シリアライザーが正しくないままにする代わりにスローできるようにする方法はありますか?ストリーム内のデータ?

これまでのところ、シリアル化時にこの状態を検出する唯一の方法は、完全信頼のリフレクションを使用して、元のデリゲートのプライベート メソッド ポインターの値と、公開されているプロパティを使用してデリゲートを再構築して得た値を比較することです。

4

1 に答える 1

3

興味深い質問です。それを検出する非常にハックな方法を1 つ見つけました。パブリック プロパティを使用してコピーを作成し、元のプロパティと等しいかどうかを確認します。動作を示すサンプルコード:

using System;
using System.Linq;
using System.IO;

class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Base");
    }
}

class Derived : Base
{
    public override void Foo()
    {
        Console.WriteLine("Derived");
    }

    public Action NonVirtualAction { get { return base.Foo; } }
    public Action VirtualAction { get { return Foo; } }
}

class Program
{
    static void Main()
    {
        var derived = new Derived();
        var virtualAction = derived.VirtualAction;
        var nonVirtualAction = derived.NonVirtualAction;

        var virtualCopy = CreateCopy(virtualAction);
        var nonVirtualCopy = CreateCopy(nonVirtualAction);

        Console.WriteLine(virtualCopy.Equals(virtualAction)); // True
        Console.WriteLine(nonVirtualCopy.Equals(nonVirtualAction)); // False
    }

    static Delegate CreateCopy(Delegate del)
    {
        // TODO: Validate it's not multi-cast
        return Delegate.CreateDelegate(del.GetType(), del.Target, del.Method);
    }
}

ただし、実際にどのように作成するかはわかりません...または、この「コピーの同等性」が誤検知を引き起こす他の状況があるかどうか.

于 2012-05-02T05:19:46.627 に答える