4

文字列メンバーを持つ C# クラスを定義しました。すべての目的のために、このクラスは string のサブクラスであると考えてください (ただし、許可されていません)。特定の形式に一致する厳密に型指定された文字列フィールドを表すために使用しています (これを大幅に簡略化しました)。

public class field
{
    private readonly string m_field;
    public field(string init_value)
    {
        //Check the syntax for errors
        if (CheckSyntax(init_value))
        {
            m_field = init_value;
        }
        else
        {
            throw new ArgumentOutOfRangeException();
        }
    }

    public override string ToString()
    {
        return m_field;
    }
}

ここで、このクラスを他の文字列 (オブジェクトまたはリテラル) と直接比較できるようにしたいと考えています。したがって、クラスに次のように実装しました。

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }

    return this.m_field == obj.ToString();
}

public override int GetHashCode()
{
    return this.m_field.GetHashCode();
}

public static bool operator ==(field x, Object y)
{
    if ((object)x == null && y == null)
    {
        return true;
    }
    else if ((object)x == null || y == null)
    {
        return false;
    }
    else
    {
        return (x.m_field == y.ToString());
    }
}

public static bool operator !=(field x, Object y)
{
    return !(x == y);
}

単体テストを作成しているときに、Assert.AreEqual に引数を渡す順序に応じて、異なる結果が得られます。

string valid = "Some String";
field target = new field(valid);
Assert.AreEqual(target, valid); // PASSES
Assert.AreEqual(valid, target); // FAILS

これは、最初のアサートで field.Equals() を呼び出しており、2 番目のアサートで String.Equals() を呼び出しているためだと思います。明らかに、私はこれに間違った角度からアプローチしています。誰でも私に洞察を与えることができますか?

もう1つ。ここで構造体 (値型) を使用することはできません。実際のケースでは、これらすべてを基本クラスで定義し、そこから継承しているためです。

4

6 に答える 6

9

基本的に、やりたいことはできませんstring。平等のためにクラスを認識させる方法はありません。再帰的にすることはできません。 の契約に従うことはできませんobject.Equals

私は個人的にそれを再設計して、タイプ自体の一部として検証を行わないようにします-それをビジネスエンティティの関連するプロパティの一部にします(またはそれらが何であれ)。

于 2009-04-27T00:28:42.107 に答える
5

これについては、有効な Javaの項目 8: オーバーライド時に一般的な規約に従う として詳細に説明されていますequals

メソッドはequals同値関係を実装します。

これは再帰的、対称的、推移的、一貫性があり、null 以外の参照 x に対してx.equals(null)は を返す必要がありfalseます。対称性を破るために引用された例は、あなたのものに似ています。

fieldclass は class を認識してstringいますが、組み込みstringクラスは を認識していませんfield。これは一方向の相互運用性であり、削除する必要があります。

于 2009-04-27T00:35:05.897 に答える
4

あなたのフィールドクラスを文字列として暗黙的に使用することを思いとどまらせ、このタイプの使用を強制します:

string valid = "Some String";
field target = new field(valid);
Assert.AreEqual(target.toString(), valid); 
Assert.AreEqual(valid, target.toString());
于 2009-04-27T00:29:27.657 に答える
0

これは String#Equals です

public override bool Equals(object obj)
{
    string strB = obj as string;
    if ((strB == null) && (this != null))
    {
        return false;
    }
    return EqualsHelper(this, strB);
}

String#Equals に String 以外の引数を指定すると、false が返されます。これを回避するために「再考」することをお勧めします。

于 2009-04-27T06:02:43.410 に答える
0

みんなのフィードバックと私自身のニーズに基づいて、考えられる解決策として次のことを提案します (次のように Equals メソッドを変更しています)。

public override bool Equals(Object obj)
{
    if (obj == null)
    {
        return false;
    }

    field f = obj as field;
    if (f != null)
    {
        return this == f;
    }
    else
    {
        return obj.Equals(this);
    }
}

これにより、値が既に存在するかどうかを判断するために Equals および GetHashCode メソッドに依存する辞書およびコレクション クラスで正しく使用できるようです。

また、これらは両方とも失敗します。

string valid = "Some String";
field target = new field(valid);
Assert.AreEqual(target, valid); // FAILS
Assert.AreEqual(valid, target); // FAILS

そして、これらは両方とも合格します:

string valid = "Some String";
field target = new field(valid);
Assert.AreEqual(target.ToString(), valid); // PASSES
Assert.AreEqual(valid, target.ToString()); // PASSES

そして、これらは両方とも合格します:

field f1 = new field("Some String");
field f2 = new field("Some String");
Assert.AreEqual(f1, f2); // PASSES
Assert.AreEqual(f2, f1); // PASSES
于 2009-04-27T00:57:58.947 に答える
-1

x または y が null かどうかを内部的に検証しようとしている場合は、object.ReferenceEquals()を使用することをお勧めします。

public static bool operator ==(field x, Object y)
{
    if (object.ReferenceEquals(x, null) && object.ReferenceEquals(y, null))
    {
        return true;
    }
    else if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null))
    {
        return false;
    }
    else
    {
        return (x.m_field == y.ToString());
    }
}
于 2013-03-18T17:09:09.350 に答える