运算符'=='不能应用于T型吗?

发布于 2024-11-03 09:31:39 字数 1380 浏览 0 评论 0原文

我认为这个方法是有效的,但我错了:

static void Equals<T>(T x, T y)
{
    return x == y;    //operator == can't be applied to type T
}

阅读规范后(v3.0中的§7.2.4和v4.0中的§7.3.4):

7.2.4 二元运算符重载解析

x 形式的运算 op y,其中 op 是可重载的 二元运算符,x 是以下表达式 类型 X,y 是类型的表达式 Y,处理如下:

  • 候选用户定义运算符的集合 由 X 和 Y 提供操作 确定算子op(x,y)。这 集合由并集组成 X 和 提供的候选算子 Y 提供的候选算子, 每个都使用以下规则确定 §7.2.5。如果 X 和 Y 是同一类型, 或者如果 X 和 Y 源自 公共基础类型,然后共享 候选运算符仅出现在 组合设置一次。

  • 如果集合 候选用户定义运算符是 不为空,则这成为集合 的候选运营商 手术。否则,预定义的 二元运算符 op 实现, 包括他们举起的形式,成为 的候选算子集合 手术。预定义的 给定运算符的实现 在描述中指定 运营商(§7.7 至 §7.11)。

  • 第 7.4.3 节的重载决议规则应用于候选运算符集合,以选择相对于参数列表 (x, y) 的最佳运算符,并且该运算符成为重载决议的结果过程。如果重载决策无法选择单个最佳运算符,则会发生编译时错误。

在步骤 2 中,我认为应该应用这个预定义的实现:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

因为 C# 中的所有内容都派生自 Object。第3步怎么会出现编译时错误呢?我认为在这种情况下不可能出现“重载解析失败选择”的情况。

编辑 当我实现这样的事情时,我想到了这个问题:

class EnumComparer<TEnum> : IEqualityComparer<TEnum>
{
    public bool Equals(TEnum x, TEnum y)
    {
        return x == y;
    }
    public int GetHashCode(TEnum obj)
    {
        return (int)obj;
    }
}

恐怕我需要构建一个表达式并在 Equals 方法中动态调用它。

I thought this method was valid but I was wrong:

static void Equals<T>(T x, T y)
{
    return x == y;    //operator == can't be applied to type T
}

After reading the specifiation (§7.2.4 in v3.0 and §7.3.4 in v4.0):

7.2.4 Binary operator overload resolution

An operation of the form x
op y, where op is an overloadable
binary operator, x is an expression of
type X, and y is an expression of type
Y, is processed as follows:

  • The set of candidate user-defined operators
    provided by X and Y for the operation
    operator op(x, y) is determined. The
    set consists of the union of the
    candidate operators provided by X and
    the candidate operators provided by Y,
    each determined using the rules of
    §7.2.5. If X and Y are the same type,
    or if X and Y are derived from a
    common base type, then shared
    candidate operators only occur in the
    combined set once.

  • If the set of
    candidate user-defined operators is
    not empty, then this becomes the set
    of candidate operators for the
    operation. Otherwise, the predefined
    binary operator op implementations,
    including their lifted forms, become
    the set of candidate operators for the
    operation. The predefined
    implementations of a given operator
    are specified in the description of
    the operator (§7.7 through §7.11).

  • The overload resolution rules of §7.4.3 are applied to the set of candidate operators to select the best operator with respect to the argument list (x, y), and this operator becomes the result of the overload resolution process. If overload resolution fails to select a single best operator, a compile-time error occurs.

In step 2 I think this predefined implementation should be applied:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

since everything in C# derives from Object. How can a compile-time error occurs in step 3? I don't think it's possible that "overload resolution fails to select" in this case.

EDIT The question came to my mind when I was implementing something like this:

class EnumComparer<TEnum> : IEqualityComparer<TEnum>
{
    public bool Equals(TEnum x, TEnum y)
    {
        return x == y;
    }
    public int GetHashCode(TEnum obj)
    {
        return (int)obj;
    }
}

I'm afraid I need to build a expression and invoke it dynamicly in Equals method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏九 2024-11-10 09:31:39

阅读规范对您来说很有好处,但您太早停止阅读了。如果你进一步阅读,你就会明白这一点:


预定义的引用类型相等运算符需要以下之一:

  • 两个操作数都是已知为引用类型或文字 null 的类型的值。此外,还存在从任一操作数的类型到另一个操作数的类型的显式引用转换。

  • 一个操作数是 T 类型的值,其中 T 是类型参数,另一个操作数是文字 null。此外,T 没有值类型约束。

除非这些条件之一为真,否则会发生绑定时错误。 (*)


该错误不是来自重载解析;错误是重载解析会选择预定义的引用类型相等运算符,而您没有引用类型。

考虑你的代码。是什么阻止 T 成为未定义相等运算符的值类型?没有什么。假设我们回到对象版本;两个操作数都会装箱到不同的位置,因此引用不相等,即使它们具有相同的内容。由于这种做法缓慢、令人困惑且错误,因此即使尝试也是违法的。

你为什么首先要尝试做这件事?如果您的方法有效,但事实并非如此,那么您的方法将比一开始就简单地使用 == 更糟糕。您打算用这种方法为世界增加什么价值?


(*) 我已向规范维护人员报告了这句话中的语法错误。

Good for you for reading the spec, but you stopped reading too soon. Had you read further you would have gotten to this bit:


The predefined reference type equality operators require one of the following:

  • Both operands are a value of a type known to be a reference-type or the literal null. Furthermore, an explicit reference conversion exists from the type of either operand to the type of the other operand.

  • One operand is a value of type T where T is a type-parameter and the other operand is the literal null. Furthermore T does not have the value type constraint.

Unless one of these conditions are true, a binding-time error occurs. (*)


The error isn't from overload resolution; the error is that overload resolution would have chosen the predefined reference type equality operator, and you don't have reference types.

Consider your code. What stops T from being a value type with no equality operator defined on it? Nothing. Suppose we fell back to the object version; both operands would box to different locations and therefore be reference-unequal, even if they had the same content. Since that is slow, confusing and wrong, it is illegal to even try.

Why are you trying to do this thing in the first place? If your method worked, which it doesn't, then your method would be worse than simply using == in the first place. What is the value you intend to add to the world with this method?


(*) I've reported the grammatical error in this sentence to the spec maintainers.

青巷忧颜 2024-11-10 09:31:39

如果它知道 where T : class 进行引用比较,那么这可能会起作用。运算符通常对泛型的支持很少,但有一些解决方法。 MiscUtil 为泛型上的运算符提供间接支持,否则 EqualityComparer.Default.Equals(x,y) 是一个不错的选择。

That would possibly work if it knew that where T : class, doing a reference comparison. Operators generally have very little support with generics, but there are workarounds. MiscUtil offers indirect support for operators on generics, otherwise EqualityComparer<T>.Default.Equals(x,y) is a good choice.

三寸金莲 2024-11-10 09:31:39

我喜欢使用 EqualityComparer.Default 来实现此目的。

它基于重写的 Equals 方法,但在可用时使用 IEquatable,避免对实现它的值类型进行装箱。

EqualityComparer<T>.Default.Equals(x, y)

I like using EqualityComparer<T>.Default for this.

It is based on the overridden Equals method, but uses IEquatable<T> when available, avoiding boxing on value types implementing it.

EqualityComparer<T>.Default.Equals(x, y)
陌生 2024-11-10 09:31:39

使用 .Equals() 方法并确保 T 实现 IComparable

use .Equals() method and be sure that the T implement IComparable

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文