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 ?
答案 0 :(得分:6)
引用类型的默认相等比较器是引用相等性,如果两个对象引用指向相同的实例(即通过单个true
创建),则仅返回new
声明)。这与测试值相等的值类型不同,如果所有数据字段相等(如您的情况中为两个),则返回true
。更多信息:Equality Comparisons (C# Programming Guide)。
如果要更改此行为,则需要在类型上实现通用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;
}
}
从覆盖==
和!=
运营商的guidelines开始(强调添加):
默认情况下,运算符
==
通过确定两个引用是否指示同一对象来测试引用相等性。因此,引用类型不必实现运算符==
以获得此功能。当一个类型是不可变的,也就是说,实例中包含的数据不能被更改时,重载运算符==
来比较值的相等而不是引用相等可能是有用的,因为作为不可变对象,它们可以被认为是只要它们具有相同的值即可。 在非不可变类型中覆盖运算符==
不是一个好主意。
答案 1 :(得分: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
等。))然后将实施。