Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在序列化和反序列化期间保持引用相等_C#_.net_Serialization - Fatal编程技术网

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

C# 如何在序列化和反序列化期间保持引用相等,c#,.net,serialization,C#,.net,Serialization,我对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.Nu

我对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中寻找类似的工具。

编辑: 不可能进行您想要的比较,因为ReferenceEqual实际上是为了检查它是否是同一个对象。从

与Equals方法和equality运算符不同 无法重写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确保两者引用同一个对象。

这根本不会发生。任何保留引用的语义仅对
序列化
/
反序列化
的单个调用有效。为了得到你想要的,你需要使用某种包装,例如

[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;
并反序列化:

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;
引用标识将永远不会在对
seralize
反序列化
的单独调用之间保留,只有
IObjectReference
有一点例外,但由于数组不实现
IObjectReference
,这是相当没有意义的

坦率地说,我想最好建议您:

  • 使用包装器对象,以便对于需要保留引用的作用域,仅执行一个
    序列化
    /
    反序列化
    调用
  • 找到一种不依赖于此的替代设计

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

我可以问一下为什么你需要它们保持不变吗?序列化的整个要点是获取数据的副本。无论如何,要获得此行为,您可以使用
IObjectReference
()。根据定义,原始和反序列化副本是不同的对象和不同的引用。@EliArbel不确定我是否理解您的问题,但它们必须是相同的(第二个为真),因为它们是相同的(第一个为真)。你能详细说明你提出的使用IObjectReference的解决方案吗?@Oded我敢肯定你还没有理解这个问题。我不会将序列化前的对象与反序列化后的对象进行比较。我在反序列化后比较两个对象@它们仍然是不同的对象,在不同的地址。它们是不同的参考文献。如果你想让它们具有值类型语义,你需要重写
==
等于
GetHashCode
等等…谢谢Marco,但这对我没有帮助。我不希望ck4和ck3引用同一个对象,我希望两个不同对象的属性在序列化之前是referenceequals,在序列化之后是referenceequals;在Java中,设计似乎是在单个OutputStream中保留引用语义,而.NET的设计则是将其限制在单个Serialize调用的范围内。我不知道这两种方法背后的原因是什么,但最好记住它们的区别。