【问题标题】:In a struct, is it valid to implement operator== via Equals, but not override Equals and GetHashCode?在结构中,通过 Equals 实现 operator== 是否有效,但不能覆盖 Equals 和 GetHashCode?
【发布时间】:2010-09-06 08:05:45
【问题描述】:

这有效吗?

public struct MyStruct
{
    public int Foo { get; set; }

    public static bool operator ==(MyStruct a, MyStruct b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(MyStruct a, MyStruct b)
    {
        return !a.Equals(b);
    }
}

(我知道这有点低效,因为 Object.Equals 默认对值类型使用反射。但它有效吗?)

我之所以问是因为 ReSharper 会突出显示它并警告我 MyStruct defines operator '==' or operator '!=' but does not provide 'Object.Equals(object o)' and 'Object.GetHashCode()'

【问题讨论】:

  • 警告是因为 Damien 所说的:它违背了开发人员的期望。
  • 恕我直言 Foo { get;放;设置器有点奇怪。值类型应该是不可变的,setter 只会在一个非常复杂的(无用的)更新网络中欺骗你。如果结构中的单个值发生变化,只需创建一个完整的新结构。例如:一个点是一个结构。而且您不能更改点的 X 或 Y。因为点是“静态”实体,所以不能“移动”它们。如果一个点发生变化,它必须是另一个点,即一个新的结构。结论:将所有属性设为只读并仅通过构造函数传递值。
  • Caspar:人们一直这么说,但我强烈反对。如果我将 setter 设为私有,struct Point 的用户只需将他们的p.X++; 更改为可读性较差的p = new Point(p.X + 1, p.Y);,或者像p = p.WithX(p.X + 1); 这样的奇怪东西,根本没有任何好处。
  • 不可变值类型的好处不仅仅是语法相关。这是因为它们比可变值类型更容易推理。 Eric Lippert 可能比任何人都能更好地解释这一点 - blogs.msdn.com/b/ericlippert/archive/2008/05/14/…。但是,如果您意识到这些弊端,并且将来与您的可变值类型交互的每个人都可以接受,那就去做吧。
  • @Alex Humphrey:可变值类型很好,只要它们永远不会改变“this”,也就是说,改变它们的唯一方法是通过公共可变字段或通过修改的公共方法通过引用传递的结构。 .net 对它们的处理存在一些限制(尤其是属性),但可以通过定义一个包含 T 类型的单个公共字段的 Holder 类来克服这些限制。

标签: c# .net operator-overloading equals equals-operator


【解决方案1】:

我认为this 可能很有趣。

【讨论】:

  • 谢谢。浮动问题很小,但值得了解。
【解决方案2】:

有效吗?是的。但它不会给你买任何东西。

【讨论】:

  • 它让我能够通过 '==' 比较两个 MyStruct 实例,不是吗?
  • @Stefan:什么,你讨厌输入Equals? ;) 我的意思是它不会给你买任何你还没有的东西(Equals)。通常使用struct,实际写出相等逻辑以获得性能优势是一个好主意;但听起来你已经知道了,基于你对反射的评论。所以,如果你真的更喜欢== 而不是Equals,但要明白除此之外它实际上并没有给你任何东西......去吧。
  • 是的,我确实更喜欢 == 而不是 Equals,因为我喜欢像对待原始类型一样对待我的值类型。谢谢。
  • @Stefan:完全合理。我仍然建议覆盖 Equals 以避免反射开销。但这只是我。
【解决方案3】:

就它编译的事实而言,它是有效的。但它是“无效的”,因为它打破了类用户的所有期望——框架设计指南规定你不应该实现只存在于运算符重载中的功能——这些方法应该可以通过其他方式访问。并且标准是 Object.Equals 和 operator== 实现相同的功能。

(Can only find the 1.1 version of the guidelines at the moment):

提供备用签名。最多 语言不支持运算符 超载。为此,它是一个 所有类型的 CLS 要求 重载运算符以包含 具有适当的辅助方法 提供 等效功能。它是一个 公共语言规范 (CLS) 要求提供这种辅助 方法。下面的例子是 符合 CLS。

【讨论】:

  • 我相信我没有违反准则。对于我的结构,Object.Equals 和 operator== 实现相同的功能,因为后者只是调用前者。
  • @Stefan:确实如此。但是 ReSharper 并不知道您已经以这种方式“链接”了这些方法。我认为一般来说,当您看到 ==!= 运算符已针对某个类型实现时,您会期望看到 Equals(因此 GetHashCode)被覆盖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多