使用 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;
}
当我尝试反序列化自引用对象时抛出异常。
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()
andGetObjectData()
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;
}