运算符'=='不能应用于'T'和'T'类型的操作数 [英] Operator '==' cannot be applied to operands of type 'T' and 'T'

查看:2335
本文介绍了运算符'=='不能应用于'T'和'T'类型的操作数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


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


在SO上已经提出了类似的问题,它们可以通过用 IEquatable<> 替换 == + Equals EqualityComparer< TEnum> .Default



然而,这两种解决方案对我来说都不起作用,因为这个问题并不重要。



我不想为 == 运算符,我正在寻找解释为什么相等运算符不适用于泛型类型。

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

//一些其他对象属性...
}

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

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



$ div $解析方案


我没有寻找==运算符的替代品,我在寻找解释为什么编译器无法弄清楚这两个泛型属性是相同类型的。


没有解释说明虚假的解释。编译器可以并且确实知道这两个泛型属性都是相同的编译时类型,您可以用类似的方式说明:

  x.Id = reference.Id; 

编译器允许这个赋值没有问题,因为它知道有一个标识转换在编译时两个完全相同类型。



所以你一定在寻找一些其他东西的解释。我认为你真正想要的是为什么运算符重载解析无法找到最佳运算符以便在类型参数上实现相等性。



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

对于不受限制的类型的平等运营商,我们不能这样做;如果 TId object ,那么必须执行引用相等。如果是字符串,则必须执行字符串相等性,如果它是int,则必须执行int等式,如果它是可空的Guid,则必须执行提升为可空的Guid相等操作,依此类推。 在C#中没有通用的相等运算符,只有一组特定的相等运算符,并且由于没有通用运算符,因此没有单一运算符可供选择运算符重载解析。因此,你会得到一个错误。

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

您已经拒绝了解决这个问题的正确解决方案,因此我们无法在不了解您拒绝标准的原因的情况下帮助您,安全,高效的解决方案。

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


In the code-sample below, the compiler complains on x.Id == reference.Id:

Operator '==' cannot be applied to operands of type 'TId' and 'TId'

Similar questions have been asked on SO and they're solved by replacing the ==-operator with IEquatable<> + Equals or EqualityComparer<TEnum>.Default.

However, both solutions don't work for me for reasons that are not important to this question.

I'm not looking for a replacement for the == operator, I'm looking for an explanation why the equality operator doesn't work for generic types.

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

解决方案

I'm not looking for a replacement for the == operator, I'm looking for an explanation why the compiler can't figure out that both generic properties are of the same type.

There is no explanation that explains a falsehood. The compiler can and does figure out that both generic properties are of the same compile-time type, which you could illustrate with something like:

x.Id = reference.Id;

The compiler would allow that assignment no problem because it knows that there is an identity conversion between two identical at compile time types.

So you must be looking for an explanation of some other thing. I think what you are really looking for is a justification for why operator overload resolution fails to find a best operator for equality on a type parameter.

The answer is: C# generic types are not C++ templates. In C++, if you have ex1 OP ex2 then the resolution of the operator that determines its semantics is performed once per construction of the template. In C#, we don't do that; we perform overload resolution on operators once and must find an operator that works for all possible substitutions of type arguments.

We cannot do that for equality operators on unconstrained types; if TId is object then reference equality must be performed; if it is string then string equality must be performed, if it is int then int equality must be performed, if it is "nullable Guid", then lifted-to-nullable Guid equality must be performed, and so on. There is no generalized equality operator in C#, only a collection of specific equality operators, and since there is no generalized operator, there's no single operator for operator overload resolution to choose. Thus you get an error.

That's why in order to do this you would typically constrain the type to implement some interface that can be used; we can generically call interface methods on generic types.

You've rejected that correct solution to the problem, and so there's not much we can do to help you here without knowing more about why you've rejected the standard, safe, efficient solution.

Now, you might note that the compiler could generate code which determines at runtime what the resolution of the overload resolution algorithm is, based on the runtime types. C# cannot do that without excessive performance cost; if you are willing to pay that cost, then cast your operands to dynamic. That tells the compiler that you are willing to accept overload resolution failures at runtime in exchange for not getting them at compile time; be careful! When you turn off a safety system, you are responsible for ensuring the type safety of your program.

这篇关于运算符'=='不能应用于'T'和'T'类型的操作数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆