在 C# 中,如果泛型类型实现接口,如何获得不同的 IEqualityComparer<T> 实例

In C# how to get different IEqualityComparer<T> instance if generic type implements an interface

我有一个具有无约束泛型类型的泛型方法。如果类型 T 实现接口,我需要获得不同的 IEqualityComparer。

代码大致如下:

public SomeState MergeCollection<T>(
    ICollection<T> thisValue, 
    ICollection<T> otherValue, 
    SomeStrategy strategy = SomeStrategy.Default, 
    IEqualityComparer<T> comparer = null)
{
    comparer = comparer ?? GetComparer<T>(strategy);
    // code using comparer
}

public IEqualityComparer<T> GetComparer<T>(SomeStrategy strategy)
{
    if(typeof(IMerge).IsAssignableFrom(typeof(T)))
    {
        return GetMergeComparer<T>(strategy);
    }
    else
    {
        return EqualityComparer<T>.Default;
    }
}

这似乎是模板特化的典型案例,但据我所知,C# 不支持此类功能。我也在考虑 static class 实现一个策略模式来交换函数以获取比较器,但是 static 将对所有类型实现,因此类型-方法字典查找是必要的。为此生成 IL 代码似乎是最后的手段,考虑到代码没有被大量使用,不值得付出努力。

更改相关方法的行为的最佳方法是什么,以便在 T 实现 IMerge 时出现特殊情况?我问是因为理论上应该可以在编译时或至少在初始化时(静态构造函数)定义行为,如果它在运行时不会改变的话。

  1. 我认为您现有的代码没有任何问题。我个人会保持原样。

    IMO 在你有证据表明它对性能至关重要之前优化它是过早的优化。

  2. 如果你真的想缓存比较的结果,你可以使用类似的东西:

    static class MergeComparerHelper<T>
    {
        static bool SupportsMerge = typeof(IMerge).IsAssignableFrom(typeof(T));
    }
    

    这利用了每个通用实例都有自己的静态字段这一事实。您可以为此使用私有嵌套 class。

    但是请注意,这仍然会产生运行时分派的成本,因为 .NET JITter 的当前实现不会为不同的引用类型 T 生成专门的实现。