9

我知道我可以通过添加自己的 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;
    }
}

我不能将其称为重载,而是称其为重载。通过运行时的魔力,它确实Equals()根据调用者的类型正确调用了正确的实现。

为什么我不能根据TwoDoubles需要覆盖和更改参数类型并让装箱通过运行时的力量发生?是因为 C# 不支持参数逆变(如果这是原因,那么为什么不支持它......似乎是一小步object o = new TwoDoubles())?

更新
说明 : object是结构继承层次结构的一部分。为什么我们不能将派生程度更高的类型指定为参数来覆盖派生程度较低的类型的实现?这将允许我们编写:

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

当变量是 TwoDouble 时,即使所述变量已被装箱为对象类型,也应调用该变量。

4

3 回答 3

13

为什么我不能覆盖并将参数类型更改为 TwoDoubles?

因为那不是类型安全的!

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

而现在你只是将一只老虎传给了一个实际上只需要一只长颈鹿的方法!

你的情况也一样。您正在使用只能采用结构的方法覆盖采用任何对象的方法;这不是类型安全的。

是因为 C# 不支持参数类型逆变吗?

不,这是因为您要求参数类型covariance,这不是类型安全的。

C# 也不支持参数类型逆变,但这不是您所要求的。

于 2012-04-30T22:50:17.327 回答
2

您可以更改 的参数(重载)Equals,就像您所做的那样,并且将根据需要进行装箱(即,每当调用 Equals(object) 时)

因为一切都从对象继承(或通过装箱隐式继承),所以您无法阻止人们能够在您的类型上使用 Equals(object)。但是,通过这样做,您会收到一个盒装电话。

如果您可以控制调用代码,请始终使用新的重载选项,即Equals(TwoDouble)

请注意,正如一位评论员已经说过的,您的代码有些不正确,请改为:

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

按照明智的建议进行编辑,您应该完成相同的任务,但在这种情况下使用 IEquatable 接口IEquatable<TwoDouble>(注意,我们所做的代码与签名匹配,因此无需更改代码)

于 2012-04-30T21:38:18.510 回答
2

如果它按照您的建议工作,那么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)

第 3 行应该发生什么?

  • 它应该调用Equals(TwoDouble)吗?如果是这样,用什么参数?一个全零的默认 TwoDouble?这违反了围绕平等的规则。
  • 它应该抛出一个强制转换异常吗?我们正确地遵循了方法签名,所以这不应该发生。
  • 它应该总是返回false吗?现在编译器必须知道 Equals 方法的含义,并且必须区别于其他方法来处理它。

没有很好的方法来实现这一点,而且它很快就会导致比它解决的问题更多的问题。

于 2012-04-30T22:16:40.600 回答