【问题标题】:Does Enumerable.ToDictionary<TSource, TKey> perform a deep copy?Enumerable.ToDictionary<TSource, TKey> 是否执行深拷贝?
【发布时间】:2013-06-25 22:16:58
【问题描述】:

我想确认https://stackoverflow.com/a/10387423/368896 的答案是正确的并且适用于以下情况:

// These IDataHolder instances contains a property "name",
// and another data member that is a large array.
// A copy constructor exists that makes a deep copy.
public MyFunction(IEnumerable<IDataHolder> columns)
{
    // Is the copy constructor called?
    this.columns = columns.ToDictionary(c => c.info.name, c => c);
}

我相当有信心没有调用了复制构造函数;即,对toDictionaary 的调用不会执行深层复制,而只会复制引用。

但是,我找不到对此的确认。

我说的对吗? toDictionary() 是否只执行浅拷贝?

(注意:我有很强的 C++ 背景,但对 C# 很陌生。)

【问题讨论】:

  • 是的,仅浅拷贝(编辑:我的意思是,复制引用。在这种情况下,它不会对 c 元素进行浅拷贝,但本质上是对 dictionary 进行浅拷贝)。如果你想做一个深拷贝,你可以调用ToDictionary重载,让你投影键/值并自己手动调用拷贝构造函数。
  • 浅拷贝。仅供参考,使用LINQPad,您可以在 30 秒内测试出这种假设。它甚至还有便携版。

标签: c#


【解决方案1】:

它只会复制对象引用而不执行任何克隆(浅或深)。

通常,它会执行 structs 的浅拷贝,尽管只是由于结构体的按值传递语义。但是在这种情况下,由于您将其键入为接口,因此我确实相信值类型 will be boxednot 浅拷贝。

如果你需要对元素进行自己的深拷贝,那么你可以使用this overload并自己调用拷贝构造函数:

public MyFunction(IEnumerable<IDataHolder> columns)
{
    //replace c.DeepCopy() with whatever the deep copying function is
    this.columns = columns.ToDictionary(c => c.info.name, c => c.DeepCopy());
}

这主要是因为 C# 没有用于深度复制的本机内置方法*。这通常是根据开发人员的需要针对每个对象实现的。

* 如果您的设计需要,您可以使用some ways to perform generalized deep copying

【讨论】:

    【解决方案2】:

    不,键和值都是按值复制的,这是一个复制。

    请注意,无论键或值是值类型还是引用类型,这都是正确的。

    为了清楚起见,按值复制的值类型意味着按值复制字段。

    为了更加清楚,对于引用类型,引用是按值复制的。由于引用是按值复制的,所以是浅拷贝。

    【讨论】:

    • 这与@ChrisSinclair 的回答相矛盾吗?他声称它们是浅拷贝;我是不是误会了什么,他的回答和你的回答有矛盾?
    • 不,我的意思是一样的。仅限浅拷贝。
    • 通过,您的意思是这些值本身就是对基础数据的引用,那么?
    • 正确。对于引用类型的变量xx 是对对象的引用。复制的是那个值,不是引用对象。