0

我无法从模板字典创建类实例的副本。似乎MemberwiseClone()留下了一些引用字典模板字段的字段。我希望能够以一种方便的方式查看是否如此,就像 Visual Studio 的 DataTips 提供的那样。

有没有办法找出引用类型对象(或其字段)的实例是否正在引用相同类型的另一个实例(在成员克隆之后)?

4

3 回答 3

2

规则是任何值类型都将被复制,任何引用类型只会复制引用。这是一个浅拷贝。

如果这不是您想要的行为,那么您需要推出自己的克隆方法。

您可能正在谈论深拷贝,在这种情况下,这将告诉您需要了解的内容:如何在 .NET(特别是 C#)中对对象进行深拷贝?

至于计算对实例的引用数,Eric Lippert 说 C# 不做引用计数C# - 获取对对象的引用数,所以你必须再次自己动手。但我不认为这是你想要做的。

于 2012-12-15T21:32:23.233 回答
0

您可以使用内存分析器手动检查引用。请参阅.NET 内存分析工具

于 2012-12-15T21:43:43.390 回答
0

Java 的一个“特性”是实际上只有一种非原始类型:对象引用,它可以以各种方式使用。虽然这使框架易于实现,但这意味着变量的类型不足以描述其含义。尽管 .net 在许多方面都对 Java 进行了改进,但它也存在着这个根本性的弱点。

例如,假设一个对象George有一个Bob类型为IList<String>[or, for Java, list<string>] 的字段。这样一个字段至少可以代表五种根本不同的事物:

  1. 它持有对一个对象的引用,该对象持有一组字符串,它永远不会允许对其进行任何更改。如果该列表的第 5 项是“Barney”,那么该列表中的第 5 项将永远不会是“Barney”以外的任何其他内容。在这种情况下,`Bob` 只封装了列表的不可变方面。此外,可以免费将引用共享给对 George 状态的该方面感兴趣的任何代码。
  2. 它持有对持有一组字符串的对象的引用,任何持有该引用的人都可以修改该字符串,但任何拥有该对象引用的实体都不会修改列表,也不允许它暴露给任何可能这样做的东西。更糟糕的是,虽然列表允许更改其内容,但实际上没有任何内容会改变这些内容。如上所述,`Bob` 仅封装了列表的不可变方面,但`George` 负责通过仅将引用公开给可以信任不修改列表的代码来维护这种不变性。
  3. 它拥有宇宙中任何地方的唯一引用,指向一个对象,该对象持有一组它可以随意修改的字符串。在这种情况下,`Bob` 封装了列表的*可变状态*。如果复制“George”,则必须创建一个新列表,其中包含与旧项目相同的项目,并为该副本提供参考。另请注意,`George` 不能将引用传递给任何可能保留引用的代码,无论该代码是否会尝试修改列表。
  4. 它持有对某个其他对象“拥有”的列表的引用,该列表将用于将项目添加到列表中以使其他对象受益,或者观察其他对象为“George”放入列表中的内容的好处。在这种情况下,`Bob` 封装了列表的 *identity*。在正确的克隆中,`Bob` 必须识别 *same list* 与原始列表中的一样。
  5. 它持有对它拥有的列表的引用,该列表将被变异,但其他一些对象也持有对列表的引用(也许他们可以为了“George”的利益将东西添加到列表中,或者也许他们可以看看 `George` 对列表所做的事情)。在这种情况下,`Bob` 封装了*可变状态和身份*。封装这两个方面的字段的存在意味着*如果没有其他对象的合作,就不可能制作语义正确的“George”副本*。

简而言之,可以Bob封装列表的可变状态、它的身份、两者或两者都不封装(除了身份之外的不可变状态是“免费赠品”)。如果它仅封装可变状态,则语义正确的副本George必须Bob引用不同的列表,该列表使用相同的内容进行初始化。如果它仅封装身份,则语义正确的副本必须Bob引用相同的列表。如果它同时封装了可变状态和不可变状态,George则无法单独正确克隆。两者都不做的字段可以被复制也可以不被复制,以方便起见。

如果可以正确确定哪些字段封装了引用对象的可变状态,哪些封装了身份,哪些两者兼而有之,那么语义上正确的克隆操作应该做什么就很明显了。不幸的是,框架中没有以这种方式对字段进行分类的标准约定,因此您必须提出自己的方法,然后再提出使用它的克隆方案。

于 2012-12-15T22:27:08.197 回答