对于引用相等,我使用object.ReferenceEquals,正如你所说,尽管你也可以将引用转换为对象并比较它们(只要它们是引用类型)。
对于 2 和 3,这真的取决于开发人员想要什么,如果他们想将平等定义为身份或价值平等。通常,我喜欢将 Equals() 保持为值相等,然后为身份相等提供外部比较器。
大多数比较项目的方法都使您能够传入自定义比较器,这就是我通常传入任何自定义相等比较器(如身份)的地方,但我就是这样。
正如我所说,这是我的典型用法,我还构建了对象模型,其中我只考虑属性的子集来表示身份,而其他属性不进行比较。
您始终可以创建一个非常简单的 ProjectionComparer,它采用任何类型并基于投影创建一个比较器,使得在需要时传递用于标识等的自定义比较器变得非常容易,并将 Equals() 方法仅用于价值.
此外,我个人通常不会重载 ==,除非我正在编写需要典型比较运算符的值类型,因为运算符重载以及如何不覆盖重载存在很多混淆。
不过,这只是我的看法 :-)
更新这是我的投影比较器,当然你可以找到许多其他的实现,但是这个对我来说效果很好,它实现了EqualityComparer<TCompare>(支持bool Equals(T, T)和int GetHashCode(T)和IComparer<T> 支持Compare(T, T)):
public sealed class ProjectionComparer<TCompare, TProjected> : EqualityComparer<TCompare>, IComparer<TCompare>
{
private readonly Func<TCompare, TProjected> _projection;
// construct with the projection
public ProjectionComparer(Func<TCompare, TProjected> projection)
{
if (projection == null)
{
throw new ArgumentNullException("projection");
}
_projection = projection;
}
// Compares objects, if either object is null, use standard null rules
// for compare, then compare projection of each if both not null.
public int Compare(TCompare left, TCompare right)
{
// if both same object or both null, return zero automatically
if (ReferenceEquals(left, right))
{
return 0;
}
// can only happen if left null and right not null
if (left == null)
{
return -1;
}
// can only happen if right null and left non-null
if (right == null)
{
return 1;
}
// otherwise compare the projections
return Comparer<TProjected>.Default.Compare(_projection(left), _projection(right));
}
// Equals method that checks for null objects and then checks projection
public override bool Equals(TCompare left, TCompare right)
{
// why bother to extract if they refer to same object...
if (ReferenceEquals(left, right))
{
return true;
}
// if either is null, no sense checking either (both are null is handled by ReferenceEquals())
if (left == null || right == null)
{
return false;
}
return Equals(_projection(left), _projection(right));
}
// GetHashCode method that gets hash code of the projection result
public override int GetHashCode(TCompare obj)
{
// unlike Equals, GetHashCode() should never be called on a null object
if (obj == null)
{
throw new ArgumentNullException("obj");
}
var key = _projection(obj);
// I decided since obj is non-null, i'd return zero if key was null.
return key == null ? 0 : key.GetHashCode();
}
// Factory method to generate the comparer for the projection using type
public static ProjectionComparer<TCompare, TProjected> Create<TCompare,
TProjected>(Func<TCompare, TProjected> projection)
{
return new ProjectionComparer<TCompare, TProjected>(projection);
}
}
这让您可以执行以下操作:
List<Employee> emp = ...;
// sort by ID
emp.Sort(ProjectionComparer.Create((Employee e) => e.ID));
// sort by name
emp.Sort(ProjectionComparer.Create((Employee e) => e.Name));