3

目前我有这个(阅读建议后编辑):

struct Pair<T, K> : IEqualityComparer<Pair<T, K>>
{
    readonly private T _first;
    readonly private K _second;

    public Pair(T first, K second)
    {
        _first = first;
        _second = second;

    }

    public T First { get { return _first; } }
    public K Second { get { return _second; } }

    #region IEqualityComparer<Pair<T,K>> Members

    public bool Equals(Pair<T, K> x, Pair<T, K> y)
    {
        return x.GetHashCode(x) == y.GetHashCode(y);
    }

    public int GetHashCode(Pair<T, K> obj)
    {
        int hashCode = obj.First == null ? 0 : obj._first.GetHashCode();

        hashCode ^= obj.Second == null ? 0 : obj._second.GetHashCode();

        return hashCode;
    }

    #endregion

    public override int GetHashCode()
    {
        return this.GetHashCode(this);
    }

    public override bool Equals(object obj)
    {
        return (obj != null) && 
    (obj is Pair<T, K>) && 
    this.Equals(this, (Pair<T, K>) obj);
    }
}

问题是 First 和 Second 可能不是引用类型(VS 实际上警告我这一点),但代码仍然可以编译。我应该在比较它们之前将它们(第一和第二)转换为对象,还是有更好的方法来做到这一点?

编辑:请注意,我希望这个结构支持值和引用类型(换句话说,按类约束不是有效的解决方案)

编辑2:至于我想要实现的目标,我希望它可以在字典中工作。其次,SRP 现在对我来说并不重要,因为这并不是这个问题的真正本质——它总是可以在以后重构。第三,与 default(T) 比较不能代替与 null 比较 - 试试看。

4

7 回答 7

3

您的 IEqualityComparer 实现应该是一个不同的类(并且绝对不是一个结构,因为您想重用引用)。

此外,您的哈希码永远不应被缓存,因为结构的默认 GetHashcode 实现(您不会覆盖)将考虑该成员。

于 2008-09-23T12:56:43.737 回答
2

如果您在比较方法中使用哈希码,如果哈希码相同,则应检查“真实值”。

bool result = ( x._hashCode == y._hashCode );
if ( result ) { result = ( x._first == y._first && x._second == y._second ); }
// OR?: if ( result ) { result = object.Equals( x._first, y._first ) && object.Equals( x._second, y._second ); }
// OR?: if ( result ) { result = object.ReferenceEquals( x._first, y._first ) && object.Equals( x._second, y._second ); }
return result;

但是比较“_first”和“_second”字段存在一点问题。默认情况下,引用类型使用前相等比较“object.ReferenceEquals”方法,他们可以覆盖它们。因此,正确的解决方案取决于您的比较方法“究竟应该做什么”。应该使用“_first”和“_second”字段的“Equals”方法,还是 object.ReferenceEquals ?或者更复杂的东西?

于 2008-09-23T13:03:05.093 回答
2

看起来您需要 IEquatable 代替:

internal struct Pair<T, K> : IEquatable<Pair<T, K>>
{
  private readonly T _first;
  private readonly K _second;

  public Pair(T first, K second)
  {
    _first = first;
    _second = second;
  }

  public T First
  {
    get { return _first; }
  }

  public K Second
  {
    get { return _second; }
  }

  public bool Equals(Pair<T, K> obj)
  {
    return Equals(obj._first, _first) && Equals(obj._second, _second);
  }

  public override bool Equals(object obj)
  {
    return obj is Pair<T, K> && Equals((Pair<T, K>) obj);
  }

  public override int GetHashCode()
  {
    unchecked
    {
      return (_first != null ? _first.GetHashCode() * 397 : 0) ^ (_second != null ? _second.GetHashCode() : 0);
    }
  }
}
于 2008-09-23T15:14:47.803 回答
0

关于警告,您可以使用 default(T) 和 default(K) 而不是 null。

我看不到您要实现的目标,但是您不应该使用哈希码来比较相等性-不能保证两个不同的对象不会具有相同的哈希码。此外,即使您的结构是不可变的,成员 _first 和 _second 也不是。

于 2008-09-23T12:57:40.537 回答
0

首先,这段代码违反了 SRP 原则。Pair 类用于保存物品,对吧?将相等性比较功能委托给它是不正确的。

接下来让我们看看你的代码:

如果参数之一为空,Equals 方法将失败 - 不好。Equals 使用了 Pair 类的哈希码,但是看一下 GetHashCode 的定义,它只是对成员哈希码的组合——它与项目的相等性无关。我希望 Equals 方法将比较实际数据。不幸的是,我现在太忙了,无法提供正确的实施。但是乍一看,您的代码似乎是错误的。如果您向我们提供您想要实现的目标的描述会更好。我相信 SO 成员将能够给你一些建议。

于 2008-09-23T12:58:33.513 回答
0

我可以建议使用 Lambda 表达式作为参数吗?这将允许您指定如何比较内部泛型类型。

于 2008-09-23T12:59:52.467 回答
0

编译时我没有收到任何警告,但我假设您正在谈论 == null 比较?演员似乎会让这一切变得更干净,是的。

PS。你真的应该为比较器使用一个单独的类。填补两个角色(作为一对和比较对)的这个类非常难看。

于 2008-09-23T13:01:39.090 回答