15

.NET4.0の新しいTuple<>インスタンスの2つで.Equalsと==を使用すると、動作が異なります。タプル<>内のオブジェクトでEqualsをオーバーライドし、.Equalsをタプルで呼び出すと、Equalsのオーバーライドが呼び出されます。タプルで==を使用すると、Equalsのオーバーライドは呼び出されません。それは設計によるものであり、それは理にかなっていますか?

編集:回答とコメントから、私は明確ではないと言うことができます。タプル<>は参照型であり、参照型の場合は== ID(ReferenceEquals)をチェックします。しかし、Tuple <>は==をオーバーライドして、含まれているオブジェクトの同等性をチェックする必要がありますか?一貫性のために、おそらくそうではありません。

たとえば、単純なオブジェクトがある場合

public class NameAndNumber
{
    public int Number { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is NameAndNumber)
        {
            NameAndNumber other = (NameAndNumber)obj;
            return Number == other.Number && Name == other.Name;
        }

        return false;
    }
}

そして、私はこのようなことをします:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
      new NameAndNumber { Name = "one", Number = 1 }, 
      new NameAndNumber { Name = "two", Number = 2 });
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
      new NameAndNumber { Name = "one", Number = 1 }, 
      new NameAndNumber { Name = "two", Number = 2 });
bool operatorResult = left == right;
bool equalsResult = left.Equals(right);
Console.Out.WriteLine("operatorResult = {0}  equalsResult = {1}", 
        operatorResult, equalsResult);

私はoperatorResult=false equalsResult=trueを取得します

私はそれを期待すべきですか?

NameAndNumberでのEqualsの実装は「正しく」なく、単純化されたサンプルコードにすぎないことを私は知っています。

IEquatable、==、!=、およびGetHashCodeの実装も試しました。同じ結果。

4

4 に答える 4

14

表示される結果は設計上の妥協によるものです。タプルはF#とC#の間で共有されるようになりました。重要な点は、すべてのタプルが実際に参照型として実装されているということですが、それはそれほど明白ではありませんでした。

タプルが深いまたは浅い同等性チェックを行うべきかどうかの決定は、2つのインターフェースに移されました:IStructuralComparableIStructuralEquatable。これらの2つは、Arrayクラスによっても実装されていることに注意してください。

于 2009-09-27T09:15:06.957 に答える
6

参照型の場合:== ID比較を実行します。つまり、両方の参照が同じオブジェクトを指している場合にのみtrueを返します。Equals()メソッドは値の比較を実行することが期待されていますが、つまり、参照が同等のオブジェクトを指している場合はtrueを返します。

==がオーバーロードされていない参照型の場合、2つの参照が同じオブジェクトを参照しているかどうかを比較します

于 2009-09-27T08:00:41.363 に答える
1

デフォルトでは、演算子==は参照の同等性をテストするため、はい、表示されている結果が期待されます。

Equals()とOperator ==(C#プログラミングガイド)をオーバーライドするためのガイドラインを参照してください。

C#には、参照の平等(IDとも呼ばれます)と値の平等の2種類の平等があります。値の平等は、一般的に理解されている平等の意味です。つまり、2つのオブジェクトに同じ値が含まれていることを意味します。たとえば、値が2の2つの整数は、値が等しくなります。参照の同等性とは、比較するオブジェクトが2つないことを意味します。

于 2009-09-27T08:01:06.387 に答える
1

デフォルトでは、==(クラス上で)は参照の同等性を意味します。つまり、それらは同じインスタンスですか。何object.ReferenceEquals(x,y)が返されるか。

独自の==/!=演算子を提供して、期待される動作を得ることができます-オーバーライドするときはオーバーライドEqualsすることも重要GetHashCodeです(そうでない場合は、キーとしての使用法を破ります-C#でEqualsメソッドがオーバーライドされるときにGetHashCodeをオーバーライドすることが重要なのはなぜですか?):

public static bool operator == (NameAndNumber x, NameAndNumber y) {
    if (x == null && y == null) return true;
    if (x == null || y == null) return false;
    return x.Number == y.Number && x.Name == y.Name;
    // or if polymorphism is important: return x.Equals(y);
}
public static bool operator !=(NameAndNumber x, NameAndNumber y) {
    return !(x == y); // lazy but works
}
public override int GetHashCode() {
    return (Name == null ? 0 : Name.GetHashCode()) +
        17 * Number.GetHashCode();
}
于 2009-09-27T08:06:25.750 に答える