在 lambda 表达式中使用相等比较器
Using equality comparer in lambda expression
我有一个地点 class 和一个坐标 class,如下所示:
class Venue
{
string Name;
Coordinate coordinate;
}
class Coordinate
{
double latitute;
double longitude;
}
现在,我希望能够select一个基于坐标的场地如下:
List<Venue> venues = GetAllVenues();
var myVenue = venues.FirstOrDefault(venue=>venue.coordinate == myCoordinate);
我有一个 IEqualityComparer 实现,但 lambda 表达式没有将 IEqualityComparer 作为参数的重载。
如何在 lambda 表达式中使用相等比较器?
编辑:
我的相等比较器如下所示:
class CoordinatesEqualityComparer:IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate x, Coordinate y)
{
return x.RowIndex == y.RowIndex && x.ColumnIndex == y.ColumnIndex;
}
public int GetHashCode(Coordinate obj)
{
return obj.GetHashCode();
}
}
当我像这样执行 Union() 操作时,即使两个列表中的坐标相同,它也无法正常工作。
List<Coordinates> coordinates;
CoordinatesEqualityComparer comparer;
coordinates.Union(someOtherListOfCoordinates, comparer);
但是,当我与自身进行联合时,它会起作用。我究竟做错了什么?是否与 GetHashCode() 实现有关?
编辑 2:
修复 GetHashCode() 方法似乎可以解决问题。
public int GetHashCode(Coordinates obj)
{
// Warning:Hack. Use two prime numbers to generate a hash based on two properties.
return obj.RowIndex.GetHashCode() * 7 + obj.ColumnIndex.GetHashCode() * 13 ;
}
你试过了吗:
var ec = new YourEqualityComparer();
var myVenue = venues.FirstOrDefault(venue =>
ec.Equals(venue.coordinate, myCoordinate));
当然,另一种方法是为 Coordinate
class 定义 ==
运算符,这样就不需要 IEqualityComparer
:
class Coordinate
{
double latitude;
double longitude;
public override bool Equals(object obj)
{
return Object.ReferenceEquals(this, obj)) ||
this == (other as Coordinate);
}
public static bool operator ==(Coordinate l, Coordinate r)
{
return ((object)l == null && (object)r == null) ||
((object)l != null && (object)r != null) &&
// equality check including epsilons, edge cases, etc.
}
public static bool operator !=(Coordinate l, Coordinate r)
{
return !(l == r);
}
}
我会实现 IEquatable<Coordinate>
、覆盖 Equals(object)、覆盖 GetHashCode() 和 == != 运算符,如下所示:
public class Coordinate : IEquatable<Coordinate>
{
public double Latitide { get; set; }
public double Longitude { get; set; }
public bool Equals(Coordinate other)
{
if (other == null)
{
return false;
}
else
{
return this.Latitide == other.Latitide && this.Longitude == other.Longitude;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as Coordinate);
}
public override int GetHashCode()
{
return this.Latitide.GetHashCode() ^ this.Longitude.GetHashCode();
}
public static bool operator ==(Coordinate value1, Coordinate value2)
{
if (!Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && !Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return true;
}
else
{
return value1.Latitide == value2.Latitide && value1.Longitude == value2.Longitude;
}
}
public static bool operator !=(Coordinate value1, Coordinate value2)
{
return !(value1 == value2);
}
}
我有一个地点 class 和一个坐标 class,如下所示:
class Venue
{
string Name;
Coordinate coordinate;
}
class Coordinate
{
double latitute;
double longitude;
}
现在,我希望能够select一个基于坐标的场地如下:
List<Venue> venues = GetAllVenues();
var myVenue = venues.FirstOrDefault(venue=>venue.coordinate == myCoordinate);
我有一个 IEqualityComparer 实现,但 lambda 表达式没有将 IEqualityComparer 作为参数的重载。
如何在 lambda 表达式中使用相等比较器?
编辑:
我的相等比较器如下所示:
class CoordinatesEqualityComparer:IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate x, Coordinate y)
{
return x.RowIndex == y.RowIndex && x.ColumnIndex == y.ColumnIndex;
}
public int GetHashCode(Coordinate obj)
{
return obj.GetHashCode();
}
}
当我像这样执行 Union() 操作时,即使两个列表中的坐标相同,它也无法正常工作。
List<Coordinates> coordinates;
CoordinatesEqualityComparer comparer;
coordinates.Union(someOtherListOfCoordinates, comparer);
但是,当我与自身进行联合时,它会起作用。我究竟做错了什么?是否与 GetHashCode() 实现有关?
编辑 2: 修复 GetHashCode() 方法似乎可以解决问题。
public int GetHashCode(Coordinates obj)
{
// Warning:Hack. Use two prime numbers to generate a hash based on two properties.
return obj.RowIndex.GetHashCode() * 7 + obj.ColumnIndex.GetHashCode() * 13 ;
}
你试过了吗:
var ec = new YourEqualityComparer();
var myVenue = venues.FirstOrDefault(venue =>
ec.Equals(venue.coordinate, myCoordinate));
当然,另一种方法是为 Coordinate
class 定义 ==
运算符,这样就不需要 IEqualityComparer
:
class Coordinate
{
double latitude;
double longitude;
public override bool Equals(object obj)
{
return Object.ReferenceEquals(this, obj)) ||
this == (other as Coordinate);
}
public static bool operator ==(Coordinate l, Coordinate r)
{
return ((object)l == null && (object)r == null) ||
((object)l != null && (object)r != null) &&
// equality check including epsilons, edge cases, etc.
}
public static bool operator !=(Coordinate l, Coordinate r)
{
return !(l == r);
}
}
我会实现 IEquatable<Coordinate>
、覆盖 Equals(object)、覆盖 GetHashCode() 和 == != 运算符,如下所示:
public class Coordinate : IEquatable<Coordinate>
{
public double Latitide { get; set; }
public double Longitude { get; set; }
public bool Equals(Coordinate other)
{
if (other == null)
{
return false;
}
else
{
return this.Latitide == other.Latitide && this.Longitude == other.Longitude;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as Coordinate);
}
public override int GetHashCode()
{
return this.Latitide.GetHashCode() ^ this.Longitude.GetHashCode();
}
public static bool operator ==(Coordinate value1, Coordinate value2)
{
if (!Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && !Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return true;
}
else
{
return value1.Latitide == value2.Latitide && value1.Longitude == value2.Longitude;
}
}
public static bool operator !=(Coordinate value1, Coordinate value2)
{
return !(value1 == value2);
}
}