2
var people = new List<Person>
{
    new Person
    {
        Id = 1,
        Name = "Atish"
    },
    new Person
    {
        Id = 2,
        Name = "Dipongkor"
    },
    new Person
    {
        Id = 1,
        Name = "Atish"
    }
};

Console.WriteLine(people.Distinct().Count());

为什么输出3

为什么不是2

4

2 回答 2

6

引用类型的默认相等比较器是引用相等,它仅true在两个对象引用指向同一个实例(即通过单个new语句创建)时返回。这与值类型不同,它测试值是否相等,并且true如果它们的所有数据字段都相等(就像您的情况中的两个)一样,则会返回。更多信息:平等比较(C# 编程指南)

如果你想改变这种行为,那么你需要IEquatable<T>在你的类型上实现泛型接口,以便它比较实例的属性是否相等。操作员随后Distinct会自动选择这个实现并产生预期的结果。

编辑IEquatable<Person>:这是您班级的示例实现:

public class Person : IEquatable<Person>
{
    public int Id { get; set; }
    public int Name { get; set; }

    public bool Equals(Person other)
    {
        if (other == null)
            return false;

        return Object.ReferenceEquals(this, other) ||
            this.Id == other.Id &&
            this.Name == other.Name;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as Person);
    }

    public override int GetHashCode()
    {
        int hash = this.Id.GetHashCode();
        if (this.Name != null)
            hash ^= this.Name.GetHashCode();
        return hash;
    }
}

从关于覆盖and运算符的指南(强调添加):==!=

默认情况下,运算符==通过确定两个引用是否指示同一个对象来测试引用是否相等。因此,引用类型不必==为了获得此功能而实现运算符。当一个类型是不可变的,即包含在实例中的数据不能改变时,重载运算符==来比较值相等而不是引用相等可能很有用,因为作为不可变对象,它们可以被认为是相同的,只要它们具有相同的价值。在非不可变类型中覆盖运算符不是一个好主意。==

于 2013-07-17T09:34:52.307 回答
3

这是因为你没有在你的班级中覆盖平等。现在,当您使用 distinct 时,它会检查引用是否相等。要改变这一点,你需要重写一些东西:operator==Equals()和 为了获得最佳结果GetHashCode()

这就是我的做法:

public static bool operator ==(Person one, Person two)
{
    return one.Id == two.Id && one.Name == two.Name;
}
public static override bool Equals(Person one, Person two)
{
    return one == two;
}
public override bool Equals(object obj)
{
    return obj is Person && ((Person)obj) == this;
}
public bool Equals(Person other)
{
    return other == this;
}
public override int GetHashCode()
{
    unchecked
    {
        return 17 * Id * 31 * Name.GetHashCode();
    }
}

此外,您可以实现IEquatable<T>接口(我在上面已经完成了,您只需要确保: IEquatable<Person>在类标题(等)的末尾添加class Person)然后就会实现。

于 2013-07-17T09:35:33.233 回答