简体   繁体   English

如何实现多个 GetHashCode 方法?

[英]How to implement multiple GetHashCode methods?

I have an interface which defines a composite key:我有一个定义复合键的接口:

public interface IKey : IEquatable<IKey>
{
    public bool KeyPart1 { get; }
    public uint KeyPart2 { get; }
    int GetHashCode(); // never gets called
}

I have an object (with an ID) to which I want to add the composite key interface:我有一个对象(带有 ID),我想向其中添加复合键接口:

public class MyObject: IEquatable<MyObject>, IKey
{
    public MyObject(int i, (bool keyPart1, uint keyPart2) key) {
    {
        Id=i;
        KeyPart1 = key.keyPart1;
        KeyPart2 = key.keyPart2;
    }
    
    public int Id { get; }
    public bool KeyPart1 { get; }
    public uint KeyPart2 { get; }

    public bool Equals(MyObject other) => this.Id == other.Id;

    public override bool Equals(object other) => other is MyObject o && Equals(o);
    public override int GetHashCode() => Id.GetHashCode();

    bool IEquatable<IKey>.Equals(IKey other) => this.KeyPart1 == other.KeyPart1
                                                && this.KeyPart2 == other.KeyPart2;
    int IKey.GetHashCode() => (KeyPart1, KeyPart2).GetHashCode(); // never gets called
}

However, when have a list of these objects and try to group them using the interface, the grouping fails:但是,当拥有这些对象的列表并尝试使用界面对它们进行分组时,分组失败:

var one = new MyObject(1, (true, 1));
var two = new MyObject(2, (true, 1));
var three = new MyObject(1, (false, 0));
var items = new[] { one, two, three };

var byId = items.GroupBy(i => i);
// result: { [one, three] }, { [two] } -- as expected

var byKey = items.GroupBy<MyObject, IKey>(i => i as IKey);

// result: { [one, two, three] } // not grouped (by 'id' or 'key')
// expected: { [one, two] }, { [three] }

I'd expected that byId would have the items grouped by the Id property, and byKey would have the items grouped by the Key property.我希望byId将按Id属性分组项目,而byKey将按Key属性分组项目。

However, byKey is not grouped at all.但是, byKey根本没有分组。 It appears that the override GetHashCode() method is always used rather than the explicitly implemented interface method.似乎总是使用覆盖GetHashCode()方法而不是显式实现的接口方法。

Is it possible to implement something like this, where the type of the item being grouped determines the hash method to use (avoiding an EqualityComparer )?是否有可能实现这样的事情,其中​​被分组的项目的类型决定了要使用的哈希方法(避免EqualityComparer )?

I noticed this problem when passing the cast objects to another method expecting an IEnumerable<IKey> .在将IEnumerable<IKey>对象传递给另一个需要IEnumerable<IKey>方法时,我注意到了这个问题。 I have a few different types implementing IKey and those with an existing GetHashCode() method did not work, while the others did.我有几种不同的类型实现了IKey ,那些具有现有GetHashCode()方法的类型不起作用,而其他类型则起作用。

Please note the objects have been simplified here and that I cannot easily change the interfaces (eg to use ValueTuple instead).请注意这里的对象已被简化,我无法轻易更改接口(例如使用ValueTuple代替)。

The GetHashCode() used in equality is either:等式中使用的GetHashCode()是:

  • the one defined via object.GetHashCode() , if no equality comparer is provided如果没有提供相等比较器,则通过object.GetHashCode()定义的
  • IEqualityComparer<T>.GetHashCode(T) , if an equality comparer is provided IEqualityComparer<T>.GetHashCode(T) ,如果提供了相等比较器

Adding your own GetHashCode() method on your own interface does nothing, and it will never be used, as it is not part of an API that the framework/library code knows about.在您自己的接口上添加您自己的GetHashCode()方法没有任何作用,并且永远不会使用它,因为它不是框架/库代码知道的 API 的一部分。

So, I'd forget about IKey.GetHashCode() , and either (or both):所以,我会忘记IKey.GetHashCode()和其中一个(或两者):

  • make MyObject.GetHashCode() provide the functionality you need, or使MyObject.GetHashCode()提供您需要的功能,或
  • provide a custom equality comparer separately to the MyObject instanceMyObject实例单独提供一个自定义的相等比较器

There are overloads of GroupBy that accept an IEqualityComparer<TKey> , for the second option.对于第二个选项,有接受IEqualityComparer<TKey>GroupBy重载。

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

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