Distinct 方法不适用于 class 与覆盖等于
Distinct method doesn't work for class with overriden Equals
我用覆盖的 Equals 创建了 class。问题是 Distinct 方法对我的 class 不起作用。
class MyClass
{
public int Item1 { get; private set; }
public int Item2 { get; private set; }
public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2);
public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
{
return false;
}
return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
}
}
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass(1, 0);
MyClass y = new MyClass(1, 0);
var list = new List<MyClass>();
list.Add(x);
list.Add(y);
bool b = x.Equals(y)); //True
var distincts = list.Distinct(); //Doesn't work, contains both
}
}
我该如何解决这个问题,为什么它不使用我的 Equals in Distinct?
您还必须覆盖 GetHashCode
:
public override int GetHashCode()
{
return Item1; // or something
}
Distinct
首先比较hashcodes,应该比实际的Equals
计算得更快。 Equals
只有在两个实例的哈希码 相等 时才会进一步评估。
您需要在 MyClass
中实现 IEquatable<MyClass>
并提供您自己的 GetHashCode
和 Equals
方法实现。
有关详细信息,请参阅 this。
class MyClass
{
public int Item1 { get; private set; }
public int Item2 { get; private set; }
public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2);
public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
{
return false;
}
return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
}
public override int GetHashCode()
{
return this.Item1;
}
}
Distinct
docs:
Returns distinct elements from a sequence by using the default equality comparer to compare values.
让我们看看what the default equality comparer does:
The Default
property checks whether type T implements the System.IEquatable<T>
interface and, if so, returns an EqualityComparer<T>
that uses that implementation. Otherwise, it returns an EqualityComparer<T>
that uses the overrides of Object.Equals
and Object.GetHashCode
provided by T.
所以基本上,要完成这项工作,您可以:
- 同时实施
GetHashCode
- 实施
IEquatable<T>
- 调用接受自定义相等比较器的
Distinct
的重载。
如果我是你,我会选择第二个,因为你需要更改的代码最少。
class MyClass: IEquatable<MyClass> {
...
public bool Equals(MyClass obj)
{
if (obj == null)
{
return false;
}
return (this.Item1 == obj.Item1 && this.Item2 == obj.Item2);
}
}
我用覆盖的 Equals 创建了 class。问题是 Distinct 方法对我的 class 不起作用。
class MyClass
{
public int Item1 { get; private set; }
public int Item2 { get; private set; }
public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2);
public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
{
return false;
}
return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
}
}
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass(1, 0);
MyClass y = new MyClass(1, 0);
var list = new List<MyClass>();
list.Add(x);
list.Add(y);
bool b = x.Equals(y)); //True
var distincts = list.Distinct(); //Doesn't work, contains both
}
}
我该如何解决这个问题,为什么它不使用我的 Equals in Distinct?
您还必须覆盖 GetHashCode
:
public override int GetHashCode()
{
return Item1; // or something
}
Distinct
首先比较hashcodes,应该比实际的Equals
计算得更快。 Equals
只有在两个实例的哈希码 相等 时才会进一步评估。
您需要在 MyClass
中实现 IEquatable<MyClass>
并提供您自己的 GetHashCode
和 Equals
方法实现。
有关详细信息,请参阅 this。
class MyClass
{
public int Item1 { get; private set; }
public int Item2 { get; private set; }
public MyClass(int item1, int item2)=>(Item1,Item2)=(item1,item2);
public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
{
return false;
}
return (this.Item1 == other.Item1 && this.Item2 == other.Item2);
}
public override int GetHashCode()
{
return this.Item1;
}
}
Distinct
docs:
Returns distinct elements from a sequence by using the default equality comparer to compare values.
让我们看看what the default equality comparer does:
The
Default
property checks whether type T implements theSystem.IEquatable<T>
interface and, if so, returns anEqualityComparer<T>
that uses that implementation. Otherwise, it returns anEqualityComparer<T>
that uses the overrides ofObject.Equals
andObject.GetHashCode
provided by T.
所以基本上,要完成这项工作,您可以:
- 同时实施
GetHashCode
- 实施
IEquatable<T>
- 调用接受自定义相等比较器的
Distinct
的重载。
如果我是你,我会选择第二个,因为你需要更改的代码最少。
class MyClass: IEquatable<MyClass> {
...
public bool Equals(MyClass obj)
{
if (obj == null)
{
return false;
}
return (this.Item1 == obj.Item1 && this.Item2 == obj.Item2);
}
}