5

虽然其他 关于使用反射绕过所有安全措施并直接调用基类的重写方法实现的其他问题通常遭到嘲笑和要求重新设计有问题的代码,但我想我偶然发现了一个奇怪但合法的用例:delegate序列化。由于我已经看到了其他问题,不要轰炸我重新设计我的代码并停止尝试绕过类型系统的建议——我正在编写一个序列化格式化程序,而那些已经获得了忽略构造函数的通行证

令我沮丧的是,即使是 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

有趣的问题。我发现了一种非常老套的检测方法:使用公共属性创建一个副本,并检查与原始文件是否相等。显示它工作的示例代码:

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 回答