简体   繁体   English

为什么我们不能在没有装箱的情况下在值类型中重写Equals()?

[英]Why cant we override Equals() in a value type without boxing?

I know I can avoid boxing by adding my own Equals implementation. 我知道我可以通过添加自己的Equals实现来避免拳击。

public struct TwoDoubles
{
    public double m_Re;
    public double m_Im;

    public TwoDoubles(double one, double two)
    {
        m_Re = one;
        m_Im = two;
    }

    public override bool Equals(object ob)
    {
           return Equals((TwoDoubles)ob);
    }
    public bool Equals(TwoDoubles ob)
    {
        TwoDoubles c = ob;
        return m_Re == c.m_Re && m_Im == c.m_Im;
    }
}

I can't call this an override as much as an overload. 我不能把这称为覆盖,就像重载一样。 By the magic of the runtime it does correctly call the correct Equals() implementation based on the type of the caller. 通过运行时的魔力,它可以根据调用者的类型正确调用正确的Equals()实现。

Why can't I override and change the parameter type to TwoDoubles and let boxing occur by the power of the runtime on an as needed basis? 为什么我不能覆盖并将参数类型更改为TwoDoubles并且根据需要通过运行时的功能进行装箱? Is it because C# doesn't support parameter contravariance (if that's the reason then why is it not supported...seems a small step from object o = new TwoDoubles() )? 是因为C#不支持参数逆变(如果这就是为什么它不支持的原因......似乎距离object o = new TwoDoubles() ?)

UPDATE UPDATE
Clarification: object is a part of the inheritance hierarchy of a struct. 澄清: object是结构的继承层次结构的一部分。 Why can we not specify a more derived type as a parameter to override an implementation from a less derived type? 为什么我们不能指定更多派生类型作为参数来覆盖较少派生类型的实现? This would allow us to write: 这将允许我们写:

 public override bool Equals(TwoDoubles ob)
 {
        TwoDoubles c = ob;
        return m_Re == c.m_Re && m_Im == c.m_Im;    
 }

Which should be called when the variable is a TwoDouble even if said variable has been boxed into an object type. 当变量是TwoDouble时应该调用哪个,即使所述变量已经被装入对象类型。

Why can't I override and change the parameter type to TwoDoubles? 为什么我不能覆盖并将参数类型更改为TwoDoubles?

Because that would not be typesafe! 因为那不是类型安全的!

class B
{
  public virtual void M(Animal animal) { ... }
}
class D : B
{
  public override void M(Giraffe animal) { ... }
}

B b = new D();
b.M(new Tiger());

And now you just passed a tiger to a method that actually only takes a giraffe! 而现在你只是把老虎传给了一种实际上只需要长颈鹿的方法!

Same thing in your case. 你的情况也一样。 You're overriding a method that takes any object with a method that can only take a struct; 您将覆盖一个方法,该方法使用只能接受结构的方法获取任何对象 ; that's not typesafe. 这不是类型安全的。

Is it because C# doesn't support parameter type contravariance ? 是因为C#不支持参数类型的逆转

No, it is because you are asking for parameter type covariance , which is not typesafe. 不,这是因为你要求参数类型协方差 ,这不是类型安全的。

C# does not support parameter type contravariance either, but that's not what you're asking for. C#也不支持参数类型的逆转,但这不是你要求的。

You can change the parameter (overload) for Equals , just as you've done, and boxing will occur as needed (ie whenever Equals(object) is called) 您可以更改Equals的参数(重载),就像您已经完成一样,并且将根据需要进行装箱(即每当调用Equals(对象)时)

Because everything inherits (or implicitly via boxing) from object, you cannot stop people from being able to use Equals(object) on your type. 因为所有东西都是从对象继承(或通过装箱隐式),所以你无法阻止人们在你的类型上使用Equals(对象)。 However, by doing so, you get a boxed call. 但是,通过这样做,您会收到一个盒装电话。

If you are in control of the calling code, then always use your new overloaded option, ie Equals(TwoDouble) 如果您控制调用代码,则始终使用新的重载选项,即Equals(TwoDouble)

Note, as one commentor already said, your code is slightly incorrect, do this instead: 请注意,正如一位评论员已经说过的,您的代码稍有不正确,请改为:

public override bool Equals(object ob)
{
  if (ob is TwoDoubles)
    return Equals((TwoDoubles)ob);
  else
    return false;
}
public bool Equals(TwoDoubles c)
{
  return m_Re == c.m_Re && m_Im == c.m_Im;
}

EDIT as has been wisely suggested, you should accomplish this same task but by using the IEquatable interface, in this case IEquatable<TwoDouble> (note, no code change necessary from what we've done as it matches the signature) 正如明智地建议编辑的那样,你应该完成同样的任务但是通过使用IEquatable接口,在这种情况下IEquatable<TwoDouble> (注意,我们在完成匹配签名时不需要更改代码)

If it worked as you suggested, where public override bool Equals(TwoDoubles c) { return m_Re == c.m_Re && m_Im == c.m_Im; } 如果它按你的建议工作,那么public override bool Equals(TwoDoubles c) { return m_Re == c.m_Re && m_Im == c.m_Im; } public override bool Equals(TwoDoubles c) { return m_Re == c.m_Re && m_Im == c.m_Im; } was all that was necessary to override the Equals(object) method, what would this code do? public override bool Equals(TwoDoubles c) { return m_Re == c.m_Re && m_Im == c.m_Im; }是所有必要重写Equals(object)方法,将这段代码做什么?

TwoDoubles td = new TwoDoubles();
object o = td;
bool b = o.Equals(new object()); // Equals(object) overridden with Equals(TwoDouble)

What should happen on line 3? 第3行会发生什么?

  • Should it call Equals(TwoDouble) ? 它应该叫Equals(TwoDouble)吗? If so, with what parameter? 如果是这样,用什么参数? A default TwoDouble with all zeros? 一个默认的TwoDouble全零? That'd violate the rules surrounding equality. 这违反了平等规则。
  • Should it throw a cast exception? 它应该抛出强制转换异常吗? We followed the method signature properly, so that shouldn't happen. 我们正确地遵循了方法签名,因此不应该发生。
  • Should it always return false? 它应该总是返回假吗? Now the compiler has to be aware of what the Equals method means , and will have to treat it differently than other methods. 现在,编译器必须知道Equals方法的含义 ,并且必须以不同于其他方法的方式对待它。

There's no good way to implement this, and it quickly causes more problems than it solves. 没有好的方法来实现它,它很快就会导致比它解决的问题更多的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM