18

我正在尝试使用显式键类型对某些对象执行 Linq GroupBy。我没有将一个传递IEqualityComparer给 GroupBy,所以根据文档:

默认相等比较器Default用于比较键。

它解释了EqualityComparer<T>.Default这样的属性:

Default属性检查 type 是否T实现了 System.IEquatable<T>泛型接口,如果是,则返回 EqualityComparer<T>使用该实现的一个。

在下面的代码中,我将一组Fred对象分组。它们有一个名为 的键类型FredKey,它实现了IEquatable<FredKey>.

这应该足以使分组工作,但分组不起作用。在下面的最后一行中,我应该有 2 个组,但我没有,我只有 3 个包含 3 个输入项的组。

为什么分组不起作用?

class Fred
{
    public string A;
    public string B;
    public FredKey Key
    {
        get { return new FredKey() { A = this.A }; }
    }
}

class FredKey : IEquatable<FredKey>
{
    public string A;
    public bool Equals(FredKey other)
    {
        return A == other.A;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var f = new Fred[]
        {
            new Fred {A = "hello", B = "frog"},
            new Fred {A = "jim", B = "jog"},
            new Fred {A = "hello", B = "bog"},
        };

        var groups = f.GroupBy(x => x.Key);
        Debug.Assert(groups.Count() == 2);  // <--- fails
    }
}
4

2 回答 2

19

来自MSDN

如果您实现 IEquatable,您还应该重写 Object::Equals(Object) 和 GetHashCode() 的基类实现,以便它们的行为与 IEquatable::Equals 方法的行为一致。如果您确实重写了 Object::Equals(Object),则在调用类上的静态 Equals(System.Object, System.Object) 方法时也会调用您的重写实现。这确保了 Equals() 方法的所有调用都返回一致的结果。

将此添加到 FredKey,它应该可以工作

public override int GetHashCode()
    {
        return A.GetHashCode();
    }
于 2009-11-06T11:58:24.523 回答
6

这是一个带有 Fiddle的完整示例。注意:该示例与问题示例略有不同。

下面的实现IEquatable可以作为TKeyin GroupBy。请注意,它包括GetHashCodeEquals

public class CustomKey : IEquatable<CustomKey>
{
    public string A { get; set; }
    public string B { get; set; }

    public bool Equals(CustomKey other)
    {
        return other.A == A && other.B == B;
    }

    public override int GetHashCode()
    {
        return string.Format("{0}{1}", A, B).GetHashCode();
    }
}

public class Custom
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
}

public static void Main()
{
    var c = new Custom[]
       {
           new Custom {A = "hello", B = "frog" },
           new Custom {A = "jim", B = "jog" },
           new Custom {A = "hello", B = "frog" },
       };

    var groups = c.GroupBy(x => new CustomKey { A = x.A, B = x.B } );
       Console.WriteLine(groups.Count() == 2);  
}
于 2015-11-20T18:25:22.200 回答