如何确定对象是否引用另一个对象?

时间:2012-12-15 21:24:52

标签: c# .net clone reference-type

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

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

3 个答案:

答案 0 :(得分:2)

规则是将复制任何值类型,并且任何引用类型将仅复制引用。这是一个浅薄的副本。

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

您可能正在谈论深层复制,在这种情况下,这将告诉您需要了解的内容:How do you do a deep copy of an object in .NET (C# specifically)?

至于计算实例引用的数量,Eric Lippert说C#不会引用引用计数C# - Get number of references to object,所以你再次必须自己动手。但我认为这不是你想做的事。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

例如,假设对象George的字段Bob的类型为IList<String> [或者,对于Java,list<string>]。至少有五个根本不同的东西,如一个领域可以代表:

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

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

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