运算符'=='不能应用于'T'和'T'类型的操作数

huy*_*itw 3 c# generics

在下面的代码示例中,编译器抱怨x.Id == reference.Id:

运算符'=='不能应用于'TId'和'TId'类型的操作数

类似的问题已经在SO上提出,并且通过用+ 或替换==-operator 来解决它们.IEquatable<>EqualsEqualityComparer<TEnum>.Default

但是,由于对此问题不重要的原因,这两种解决方案对我都不起作用.

我不是在寻找==操作符的替换,我正在寻找解释为什么相等运算符不适用于泛型类型.

public class Object<TId>
{
    public TId Id { get; set; }

    // Some other object properties...
}

public class ObjectReference<TId>
{
    public TId Id { get; set; }
}

public class ObjectStore<TId>
{
    private List<Object<TId>> _store = new List<Object<TId>>();

    public Object<TId> FindByReference(ObjectReference<TId> reference)
    {
        return _store.FirstOrDefault(x => x.Id == reference.Id);
    }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 9

我不是在寻找==运算符的替代品,我正在寻找一个解释,为什么编译器无法弄清楚这两个泛型属性是否属于同一类型.

没有解释说明虚假.编译器可以并且确实发现两个泛型属性都具有相同的编译时类型,您可以通过以下方式说明:

x.Id = reference.Id;
Run Code Online (Sandbox Code Playgroud)

编译器将允许该赋值没有问题,因为它知道在两个相同的编译时类型之间存在标识转换.

所以你必须寻找其他东西的解释.我认为你真正想要的是为什么运算符重载解析无法找到类型参数上相等的最佳运算符的理由.

答案是:C#泛型类型不是C++模板.在C++中,如果您有,ex1 OP ex2每个构造模板执行一次确定其语义的运算符的分辨率.在C#中,我们不这样做; 我们对运算符执行一次重载解析,并且必须找到一个适用于所有可能的类型参数替换的运算符.

对于无约束类型的等式运算符,我们不能这样做; if TId是否object必须执行引用相等; 如果它是字符串则必须执行字符串相等,如果它是int则必须执行int相等,如果它是"可空的Guid",则必须执行提升到可以为空的Guid相等,依此类推. C#中没有通用的等于运算符,只有一组特定的相等运算符,并且由于没有通用运算符,因此没有单个运算符可供选择运算符重载决策.因此,您会收到错误.

这就是为什么为了做到这一点,你通常会限制类型来实现一些可以使用的接口; 我们通常可以在泛型类型上调用接口方法.

你已经拒绝了这个问题的正确解决方案,因此我们没有太多可以帮助你的事情,而不知道为什么你拒绝了标准,安全,有效的解决方案.

现在,您可能会注意到编译器可以生成代码,该代码在运行时根据运行时类型确定重载决策算法的分辨率.没有过高的性能成本,C#不能做到这一点; 如果你愿意支付这笔费用,那就把你的操作数投入dynamic.这告诉编译器你愿意在运行时接受重载解析失败,以换取在编译时没有得到它们; 小心!当您关闭安全系统时,您有责任确保程序的类型安全.

  • 你是对的,我没有意识到没有一个“==”运算符适用于所有类型。这就是我为了充分理解这一限制而寻找的答案。每天还在学习。感谢您抽出时间埃里克! (2认同)