简体   繁体   English

C#Dictionary <>和可变键

[英]C# Dictionary<> and mutable keys

I was told that one of the many reasons strings were made immutable in the C# spec was to avoid the issue of HashTables having keys changed when references to the string keys altered their content. 有人告诉我,在C#规范中字符串变为不可变的原因之一是为了避免在对字符串键的引用改变其内容时HashTables的密钥发生变化的问题。

The Dictionary<> type allows reference types to be used as a key. Dictionary <>类型允许将引用类型用作键。 How does the dictionary avoid the issue of altered keys that lead to "misplaced" values? 字典如何避免导致“错放”值的更改密钥的问题? Is there a memberwise clone made of an object when used as a key? 当用作键时,是否存在由对象构成的成员克隆?

The Dictionary<TKey,TValue> type makes no attempt to protect against the user modifying the key used. Dictionary<TKey,TValue>类型不会尝试防止用户修改所使用的密钥。 It is purely left up to the developer to be responsible in not mutating the key. 纯粹由开发人员负责不改变密钥。

If you think about this a bit this is really the only sane route that Dictionary<TKey,TValue> can take. 如果你想到这一点,这真的是Dictionary<TKey,TValue>可以采取的唯一理智的路线。 Consider the implication of doing an operation like a memberwise clone on the object. 考虑在对象上执行类似成员克隆的操作的含义。 In order to be thorough you'd need to do a deep clone because it will be possible for an object referenced in the key to also be mutated and hence affect the hash code. 为了彻底,您需要进行深度克隆,因为密钥中引用的对象也可能会发生变异,从而影响哈希代码。 So now every key used in the table has it's full object graph cloned in order to protect against mutation. 所以现在表中使用的每个键都有克隆的完整对象图,以防止突变。 This would be both buggy and possibly a very expensive operation. 这将是错误的并且可能是非常昂贵的操作。

If you're using a mutable reference type as a key, the default implementation of GetHashCode() will guarantee hash equality regardless of object state (ie the hash is tied to the reference, not the state). 如果您使用可变引用类型作为键,则GetHashCode()的默认实现将保证哈希相等,而不管对象状态如何(即哈希与引用相关联,而不是与状态相关联)。 You're correct, however, that a mutable type with value equality semantics (where GetHashCode presumably depends on state) is a bad choice for a dictionary key. 但是,你是正确的,具有值相等语义的可变类型(其中GetHashCode可能取决于状态)是字典键的错误选择。

The Dictionary<> class does nothing to protect itself against a mutable key object being changed. Dictionary<>类不会保护自己免受正在更改的可变键对象的影响。 It's up to you to know whether or not the class you're using as a key is mutable, and to avoid it if possible. 由您来决定您使用的关键类是否可变,并尽可能避免使用它。

If a reference type does not override Equals/GetHashCode, a Dictionary using the default comparator won't care about any of the key objects' fields or properties, and thus won't notice or care if they change. 如果引用类型不重写Equals / GetHashCode,则使用默认比较器的Dictionary将不关心任何关键对象的字段或属性,因此不会注意或关注它们是否发生更改。 It's simplest to think of the default GetHashCode method as returning a number related to an "object ID", and the default Equals method as comparing "object id's". 最简单的方法是将默认的GetHashCode方法视为返回与“对象ID”相关的数字,并将默认的Equals方法视为比较“对象ID”。 Indeed, in a system limited to two billion or fewer objects, GetHashCode could simply return an object ID, but for various reasons it might do other things as well. 实际上,在一个限制为20亿或更少对象的系统中,GetHashCode可以简单地返回一个对象ID,但由于各种原因,它也可以做其他事情。

If the only part of an object that is examined by Equals or GetHashCode is the object ID, then for purposes of those functions, all objects are immutable. 如果Equals或GetHashCode检查的对象的唯一部分是对象ID,那么对于这些​​函数,所有对象都是不可变的。 Once an object is created, it will always have the same ID, and that ID will never be used for any other object until all traces of the former object ID have vanished from the universe. 一旦创建了一个对象,它将始终具有相同的ID,并且该ID将永远不会用于任何其他对象,直到前一个对象ID的所有痕迹都从Universe中消失。

It does not avoid this situation. 它不能避免这种情况。 It's up to the calling code to enforce this: 由调用代码来强制执行此操作:

As long as an object is used as a key in the Dictionary<TKey, TValue> , it must not change in any way that affects its hash value. 只要对象在Dictionary<TKey, TValue>用作键,就不能以任何影响其哈希值的方式进行更改。 Every key in a Dictionary<TKey, TValue> must be unique according to the dictionary's equality comparer. 根据字典的相等比较器Dictionary<TKey, TValue>中的每个键必须是唯一的。 A key cannot be null , but a value can be, if the value type TValue is a reference type. 如果值类型TValue是引用类型,则键不能为null ,但值可以是。

(From MSDN ) (来自MSDN

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM