为什么C#使用结构而不是内部KeyValuePairs的类

时间:2015-03-25 17:49:05

标签: c# .net class struct equality

我的印象结构应该用于:

  • 短期值(通常在整个物体生命中存活)
  • 大小不超过16个字节(通常是字符串键,很容易超过这个

另外,这些都不是堆分配的,因为你显然无法在堆栈中存储所有这些大的键值节点?甚至可能会有一些拳击费用。

我问的原因是因为我实现了一个使用类似结构的数据结构,我注意到使用类而不是结构有很多速度提升,并且想知道微软的理由是做什么的除了可能的不变性之外。

但即便如此,当发生这种情况时,返回复制的KeyValueNode可能会更快,不是吗?

来源:http://referencesource.microsoft.com/#mscorlib/system/collections/generic/keyvaluepair.cs,8585965bb176a426

3 个答案:

答案 0 :(得分:2)

创建一个足够小的结构,不会杀死堆栈,总是比创建相同大小的更便宜。将任何大小的结构传递给期望引用类型的方法总是比传递堆对象引用更昂贵。访问数组中保存的结构的成员通常比访问由存储在数组中的引用所标识的类对象的成员更便宜。复制大型结构比复制小型结构或堆对象引用更昂贵,但除非复制结构的次数超过两次,否则这种复制的成本不会超过创建该大小的类对象所带来的额外成本。除非一个对象真的很大,否则在额外的复制成本超过类对象构造开销的节省之前需要多次复制。

如果Dictionary要维护一组引用键值对象对象,那么让它的枚举器返回对该数组中项目的引用的成本会略低于让它返回一个副本的成本。来自包含键 - 值对结构的数组中的项。此外,当扩展字典时,复制对键值对象的引用的成本将略微低于复制键值对结构的成本。然而,增加项目到字典的一般成本将增加,从中检索值(而不是键值对)的成本也会增加。对于字典的大多数常见用例,使用键值对象最终会比使用结构更昂贵。

答案 1 :(得分:0)

除了你给出的原因之外,你可能使用结构的另一个重要原因是,当使用Equals()方法时,两个具有相同值的结构被视为相等方法不被覆盖因为它们是值类型,就像类型int的两个变量具有相同的值一样。引用the documentation for KeyValuePair,您可以看到Equals方法继承自ValueType,当比较两个值时,它会执行此操作。这对于键/值对很重要,因为它们执行的作业,即在集合中使用唯一键保存值,并且针对这些对的操作使用Equals方法下的struct MyStruct { public System.IO.Stream Value { get; set; } } 方法。检查集合中是否已有钥匙时,引擎盖。

例如,假设你有这个结构:

var input = System.IO.File.OpenRead(myPath);
var myFirstStruct = new MyStruct();
var mySecondStruct = new MyStruct();
myFirstStruct.Value = input;
mySecondStruct.Value = input;
System.Diagnostics.Debug.Print(myFirstStruct.Equals(mySecondStruct).ToString());

以下将输出" True":

class MyClass
{
    public System.IO.Stream Value { get; set; }
}

但是,如果我有这个课:

var input = System.IO.File.OpenRead(myPath);
var myFirstClass = new MyClass();
var mySecondClass = new MyClass();
myFirstClass.Value = input;
mySecondClass.Value = input;
System.Diagnostics.Debug.Print(myFirstClass.Equals(mySecondClass).ToString());

然后输出" False":

{{1}}

看到区别?在第二个示例中,两个实例相等,因为类是引用类型,而不是值类型。

答案 2 :(得分:0)

类是引用类型。结构是值类型。在语义上(也可能在逻辑上)有意义的是KeyValuePair中的值可以作为值类型访问。