繁体   English   中英

如何在序列化和反序列化期间保持引用相等

[英]How to maintain reference equality during serialization and deserialization

我在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 };
}

当我运行此代码时,我得到TrueFalse 我正在寻找可以使用的功能,这些功能可以为TrueTrue

注意#1:我检查了周围,并看到了有关使用DataContractSerializerMarshalByRefObject参考,但是我看不到如何将这些功能应用于此问题;

注意#2:我知道我可以编写自己的自定义序列化逻辑,但是我想避免这种情况,而是使用默认序列化。 例如,如果我在Java中使用默认序列化,则在这种情况下我将获得TrueTrue ,并且我正在.NET中寻找类似的工具。

这根本不会发生。 任何保留引用的语义仅对一次调用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;

除了IObjectReference略有例外,在IObjectReference分别对SerailizeDeserialize调用之间,都不会保留引用身份,但是由于数组未实现IObjectReference ,因此这很IObjectReference

坦白说,我怀疑您最好选择以下两种方法之一:

  • 使用包装对象,因此对于需要保留引用的范围,只有一个Serialize / Deserialize调用在起作用
  • 找到不依赖于此的替代设计

我还应该添加脚注,我通常建议人们不要过度使用BinaryForamtter我已经看到太多的人丢失数据或陷入混乱,通常是在他们的代码版本之间进行迭代时。 改变不是很容易。

编辑:不可能进行所需的比较,因为ReferenceEqual实际上是要检查它是否是同一对象。 来自msdn

与Equals方法和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引用了不同的对象。 为了获得与序列化之前相同的结果,请shuold执行

Check ck3 = (Check)oos.Deserialize(fs);
Check ck4 = ck3;

在这里,创建了一个新对象ck3,并且ck4 = ck3确保两者都引用同一对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM