You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# IEqualityComparer<T>转object比较器抛InvalidCastException

核心原因

泛型协变/逆变特性仅对引用类型生效,值类型不支持泛型变体转换。
IEqualityComparer<in T>的in标记确实代表该泛型参数支持逆变,但这个能力有明确的适用前提:转换前后的泛型参数必须都是引用类型,且存在合法的引用转换关系。这个限制是.NET运行时层面的统一规则,所有标记了协变/逆变的泛型接口、委托,只要泛型参数位置是值类型,对应的变体转换全部无效——比如你同样无法将IEnumerable<int>直接转换为IEnumerable<object>,哪怕IEnumerable<out T>是协变接口。
你代码中实现的是IEqualityComparer<double>,double是值类型,值类型和object之间的转换属于装箱/拆箱转换,会生成新的托管对象,不满足泛型变体要求的引用同一性(即转换前后引用指向同一内存地址、内存布局完全一致),因此强制转换必然抛出InvalidCastException。

关于自定义class测试失败的说明

如果使用自定义引用类型(class)实现IEqualityComparer<T>后,向IEqualityComparer<object>转换依然失败,属于测试写法错误。引用类型下逆变是可以正常工作的,参考如下可正常运行的示例:

public class Foo { }
public class FooEqualityComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo a, Foo b) => ReferenceEquals(a, b);
    public int GetHashCode(Foo a) => a.GetHashCode();
}

// 以下转换可以正常执行,不会抛出异常
var fooComparer = new FooEqualityComparer();
var objectComparer = (IEqualityComparer<object>)fooComparer;
适配方案

针对当前MVVM场景下必须传入IEqualityComparer<object>、且实际传入值均为double的情况,最直接的方案是写一层薄包装,内部做拆箱后调用原有的值类型比较器即可,包装层开销极低:

public class ObjectWrappedDoubleComparer : IEqualityComparer<object>
{
    private readonly IEqualityComparer<double> _inner;
    public ObjectWrappedDoubleComparer(IEqualityComparer<double> inner) => _inner = inner;

    bool IEqualityComparer<object>.Equals(object x, object y)
    {
        return _inner.Equals((double)x, (double)y);
    }

    int IEqualityComparer<object>.GetHashCode(object obj)
    {
        return _inner.GetHashCode((double)obj);
    }
}

使用时直接包装原有比较器实例即可:

var doubleComparer = new DoubleEqualityComparer();
IEqualityComparer<object> objectComparer = new ObjectWrappedDoubleComparer(doubleComparer);

内容的提问来源于stack exchange,提问作者Marnix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:45:30