【问题标题】:C# Struct dictionary key not working with array memberC# Struct 字典键不适用于数组成员
【发布时间】:2014-09-24 15:02:15
【问题描述】:

我正在尝试创建一个在构造过程中采用可变数量参数的结构,目的是将此对象用作字典键(我的 .Net 版本不支持 Tuple 类型):

struct TupleKey
{
    int[] args;
    public TupleKey(params int[] args) { this.args = args; }
}

但是,当我将此 struct 用作字典的键时,ContainsKey 方法返回 false。

var d = new Dictionary<TupleKey, int>();
d.Add(new TupleKey(1, 1), 1);
Console.WriteLine(d.ContainsKey(new TupleKey(1,1)));  // false!?

发生了什么事?在结构中使用可变对象(如数组)有问题吗?

【问题讨论】:

  • 因为它是一个动态数组,需要指定它的大小。
  • @karlsweeney 不,根本不是这样。

标签: c# struct


【解决方案1】:

自定义struct 的默认相等和哈希码实现将基于其成员的默认相等和哈希码方法,在您的情况下是一个数组。该数组使用基于引用的标识,而不是基于值的标识。如果您希望具有相同值的不同数组相等,则需要覆盖 EqualsGetHashCode 以依赖于数组的值。

【讨论】:

  • 这是有道理的。我曾认为Structs 按值而不是按引用进行比较(当成员是引用类型时,这显然不是真的)。谢谢你,Servy。
  • @gjdanis 结构正在按值进行比较。在这种特殊情况下,结构的值 是一个引用
【解决方案2】:

一般来说,.NET 中的类型尝试定义Equals,这样如果xy 是类的私有字段,则x.Equals(y) 的值不能更改,除非该类写入这些字段。如果xy 是可变引用类型,这意味着x.Equals(y) 可以为真的唯一方法是xy 标识相同的对象。如果x.Equals(y)xy 识别状态恰好相同的不同对象时返回true,并且引用这些对象之一的其他地方的代码要修改其状态,那么外部代码可能会更改x.Equals(y) 的值,而无法访问 xy

我认为可以合理地认为 .NET 缺乏“不可变数组”类型;如果存在这样的类型,那么它们是不可变的,可以保证如果两个实例曾经包含相同的项目,它们将永远这样做。但是,由于 .NET 没有任何此类类型,因此有必要忍受这种限制。

最好的办法可能是让结构的构造函数构造一个数组,该数组比传入的数组长一个元素,并包含原始数组内容的副本以及其中值的哈希值。然后,该数组将永远不会暴露给外部代码,因此可以保证永远不会被修改。您的 equals 方法可以检查与您的类型进行比较的对象是否是相同类型的另一个结构,如果是,则检查数组的长度是否相同,存储的哈希值是否匹配,如果是,是否所有其他项目匹配。然后,您的 GetHashCode 值应返回您存储在额外数组插槽中的哈希值。如果你这样做,你还应该实现IEquatable&lt;yourOwnType&gt;

请注意,虽然可以使用字段而不是数组槽来保存哈希值,但使用数组槽会更有效,并且可以避免不正确的多线程代码创建结构实例的可能性其哈希值与数组的内容不一致。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2020-04-03
    • 2023-04-04
    • 2021-08-12
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多