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();
    }
}

重构完成。

参考:

posted @ 2025-05-24 08:29  dudu  阅读(74)  评论(0)    收藏  举报