C# 实现通用的 IdEqualityComparer
这是昨天在园子博客后台开发中遇到的一次代码重构。
两个列表进行 union
posts = [.. pinnedPosts.Union(posts, new IdEqualityComparer())];
需要自己实现一个 EqualityComparer,基于 Id 字段进行进行比较,默认基于对象引用进行比较,不是我们期望的。
IdEqualityComparer 的实现如下
internal class IdEqualityComparer : IEqualityComparer<BlogPost>
{
public bool Equals(BlogPostModel x, BlogPostModel y)
{
return ReferenceEquals(x, y) || (x is not null && y is not null && x.Id == y.Id);
}
public int GetHashCode(BlogPostModel obj)
{
return obj is null ? 0 : obj.Id.GetHashCode();
}
}
上面的实现虽然可以工作,但将 IdEqualityComparer 与具体比较的对象类型绑定了,每个被比较的对象都需要实现自己的 IdEqualityComparer,太啰嗦了。
重构实现一个通用的 IdEqualityComparer 是必须的。
泛型可以解决与具体对象类型绑定的问题,但是仅有泛型还不够,因为需要比较 Id 字段,也就是被比较的对象必须要有 Id 字段,这可以通过引入一个接口解决。
public interface IIdentifiable<T>
{
T Id { get; set; }
}
最后重构出来的通用 IdEqualityComparer 实现
public class IdEqualityComparer<TComparee, TId> : IEqualityComparer<TComparee>
where TComparee : IIdentifiable<TId>
{
public bool Equals(TComparee? x, TComparee? y)
{
return ReferenceEquals(x, y) ||
(x is not null && y is not null &&
(x is IIdentifiable<TId> xx) && (y is IIdentifiable<TId> yy) &&
xx.Id is not null && yy.Id is not null &&
xx.Id.Equals(yy.Id));
}
public int GetHashCode(TComparee obj)
{
if (obj is null)
return 0;
if (obj is IIdentifiable<TId> x && x.Id is not null)
{
return x.Id.GetHashCode();
}
return obj.GetHashCode();
}
}
重构完成。
参考: