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()です)?

UPDATE
の 明確化: 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#がパラメーター型の共変性をサポートしていないためですか?

いいえ、タイプセーフではないパラメータータイプの共分散を要求しているためです。

C#はパラメーター型の共変性もサポートしていませんが、それはあなたが求めているものではありません。

于 2012-04-30T22:50:17.327 に答える
2

と同じように、のパラメータ(オーバーロード)を変更できEqualsます。必要に応じて(つまり、Equals(object)が呼び出されるたびに)ボクシングが行われます。

すべてがオブジェクトから継承する(または暗黙的にボクシングを介して)ため、ユーザーがタイプでEquals(オブジェクト)を使用できるようにすることを阻止することはできません。ただし、そうすることで、ボックス化された呼び出しを取得します。

呼び出し元のコードを管理している場合は、常に新しいオーバーロードされたオプションを使用してください。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 に答える