使用 ISerializationSurrogate 反序列化自引用对象时抛出异常

Exception threw out when deserializing self-reference objects while using ISerializationSurrogate

当我尝试反序列化自引用对象时抛出异常。

System.Runtime.Serialization.SerializationException: "The object with ID 1 is referenced in the link address information, but the object does not exist."

这是我的代码:

class MySerializationSurrogate : ISerializationSurrogate {
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        Console.WriteLine("MySerializationSurrogate.GetObjectData()");
    }
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
        Console.WriteLine("MySerializationSurrogate.SetObjectData()");
        var it = info.GetEnumerator();
        while (it.MoveNext()) {
            Console.WriteLine($"{it.ObjectType} {it.Name} {it.Value}");
        }
        return obj;
    }
}

[Serializable]
class Test {
    int prop { get; set; } = 123321;
    Test me { get; set; }
    public Test() { me = this; }
}

class Program {

    static void Save() {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream fs = new FileStream("E:\a.txt", FileMode.Create);
        Test ch = new Test();
        bf.Serialize(fs, ch);
        fs.Close();
    }

    static void Read() {
        BinaryFormatter bf = new BinaryFormatter();
        SurrogateSelector mss = new SurrogateSelector();
        mss.AddSurrogate(typeof(Test), bf.Context, new MySerializationSurrogate());
        bf.SurrogateSelector = mss;
        FileStream fs = new FileStream("E:\a.txt", FileMode.Open);
        object ch = bf.Deserialize(fs);
        fs.Close();
    }

    static void Main(string[] args) {
        Save();
        Read();
        Console.ReadLine();
    }
}

There wasn't any out put in my console, so I think SetObjectData() and GetObjectData() hasn't been called.

If I delete mss.AddSurrogate(typeof(Test), bf.Context, new MySerializationSurrogate()); the code will run successfully.

If I remove Test.me the code will run successfully.

I tried to find out what's wrong, so I created a circular reference like this:

a.p=b;b.p=a;Serialize(fs,a);

然后反序列化,没有任何异常。所以支持循环引用。

似乎当你使用用户定义的surrogate并尝试反序列化一个具有自指针的对象时,会抛出异常。

连你的代理人都没有叫到。

怎么了?

我能做到这一点的唯一方法是使用哨兵手动编码自引用有效负载:

    const string Self = "SELF";
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var test = (Test)obj;
        info.AddValue("prop", test.prop);
        if (test.me is null) { }
        else if (ReferenceEquals(test.me, test))
        {
            info.AddValue("me", Self);
        }
        else
        {

            info.AddValue("me", test.me);
        }


    }
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        var it = info.GetEnumerator();
        var test = (Test)obj;
        while (it.MoveNext())
        {
            switch (it.Name)
            {
                case "prop":
                    test.prop = (int)it.Value;
                    break;
                case "me":
                    switch(it.Value)
                    {
                        case string s when s == Self:
                            test.me = test;
                            break;
                        case Test t:
                            test.me = t;
                            break;
                    }
                    break;
            }
        }
        return obj;
    }