我在C#/ .NET中遇到序列化的问题,如果我在一个流中序列化多个对同一对象的引用,则在反序列化后这些引用不再相等。我正在使用默认的二进制序列化。绊倒我的代码是:
Check ck1 = new Check();
Check ck2 = new Check();
ck1.Numbers = new int[] { 11, 12, 13 };
ck2.Numbers = ck1.Numbers;
Console.WriteLine(ReferenceEquals(ck1.Numbers, ck2.Numbers));
FileStream fs = new FileStream("d:\\deleteme-check3.txt", FileMode.Create, FileAccess.Write);
BinaryFormatter oos = new BinaryFormatter();
oos.Serialize(fs, ck1);
oos.Serialize(fs, ck2);
fs.Flush();
fs.Close();
fs = new FileStream("d:\\deleteme-check3.txt", FileMode.Open, FileAccess.Read);
oos = new BinaryFormatter();
Check ck3 = (Check)oos.Deserialize(fs);
Check ck4 = (Check)oos.Deserialize(fs);
Console.WriteLine(ReferenceEquals(ck3.Numbers, ck4.Numbers));
宣言是
[Serializable]
class Check
{
public int[] Numbers = new int[] { 0, 1, 2 };
}
当我运行此代码时,我得到True
和False
。我正在寻找可以使用的功能True
和True
。
注意#1:我已经查看并查看了使用DataContractSerializer
和MarshalByRefObject
的引用,但我没有看到如何将这些功能应用于此问题;
注意#2:我知道我可以编写自己的自定义序列化逻辑,但我想避免使用它,而是使用默认序列化。例如,如果我在Java中使用默认序列化,那么在这种情况下我会得到True
和True
,我正在寻找.NET中的类似工具。
答案 0 :(得分:3)
这根本不会发生。任何引用保留语义仅对单个Serialize
/ Deserialize
的调用有效。为了获得你想要的东西,你需要使用某种包装器,即
[Serializable]
public class HazTwo {
public Check First {get;set;}
public Check Second {get;set;}
}
然后序列化:
var obj = new HazTwo { First = ck1, Second = ck2 };
oos.Serialize(fs, obj);
和反序列化:
var newObj = (HazTwo)oos.Deserialize(fs);
var ck3 = newObj.First;
var ck4 = newObj.Second;
Serailize
或Deserialize
的单独调用之间不会保留引用标识,但IObjectReference
略有例外 - 但由于数组未实现IObjectReference
,这是没有实际意义的。
坦率地说,我怀疑你最好建议:
Serialize
/ Deserialize
次调用我还应该添加脚注,我通常会建议人们不要过度使用BinaryForamtter
- 我看到太多人丢失数据或陷入混乱,通常是他们在代码版本之间进行迭代。它不太适合改变。
答案 1 :(得分:0)
编辑: 不可能进行你想要的比较,因为ReferenceEqual实际上是要检查它是同一个对象。来自msdn
与Equals方法和相等运算符不同 ReferenceEquals方法无法重写。因此,如果你 想要测试两个对象引用是否相等而且不确定 执行Equals方法,可以调用 ReferenceEquals方法。但是,请注意,如果objA和objB是值 类型,它们在传递给ReferenceEquals之前被装箱 方法
因此,如果您想要使用ReferenceEqual,那么就可以按照下面的描述进行操作。
原帖
在第一次检查时,你会因为这些陈述而成真
ck1.Numbers = new int[] { 11, 12, 13 };
ck2.Numbers = ck1.Numbers;
第二行使得ck2引用与ck1相同的对象。
关于反序列化,你可以
Check ck3 = (Check)oos.Deserialize(fs);
Check ck4 = (Check)oos.Deserialize(fs);
你在这里做的是创建两个新对象,ck3和ck4引用不同的对象。要获得与序列化之前相同的结果,请执行
Check ck3 = (Check)oos.Deserialize(fs);
Check ck4 = ck3;
这里创建了一个新对象ck3,ck4 = ck3确保两者都引用同一个对象。