web-dev-qa-db-ja.com

'=='演算子のオーバーロードで、無限再帰なしでnullをチェックするにはどうすればよいですか?

以下は、==演算子のオーバーロードメソッドで無限再帰を引き起こします

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

Nullをチェックするにはどうすればよいですか?

109
Andrew Jones

ReferenceEqualsを使用します:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}
133
Abe Heidebrecht

オーバーロードメソッドでオブジェクトにキャストします。

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}
19
Andrew Jones

ReferenceEqualsを使用します。 MSDNフォーラム から:

public static bool operator ==(Foo foo1, Foo foo2) {
    if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
    if (ReferenceEquals(foo2, null)) return false;
    return foo1.field1 == foo2.field2;
}
8
Jon Adams

Object.ReferenceEquals(foo1, null)を試してください

とにかく、==operatorをオーバーロードすることはお勧めしません。参照の比較に使用し、「セマンティック」比較にはEqualsを使用する必要があります。

4

C#7以降を使用している場合は、null定数パターンマッチングを使用できます。

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

これにより、オブジェクトを呼び出すものよりも少しすっきりとしたコードが得られます。ReferenceEquals(foo1、null)

4
jacekbe

bool Equals(object obj)をオーバーライドし、演算子_==_とFoo.Equals(object obj)で同じ答えを返したい場合は、通常、次のように_!=_演算子を実装します。

_public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}
_

演算子_==_は、すべてのnullチェックを実行した後、2つが等しい場合に実際のチェックを実行するためにオーバーライドしたfoo1.Equals(foo2)を呼び出すことになります。

4
Hallgrim

この場合、実際にはnullに対してチェックするより簡単な方法があります。

if (foo is null)

それでおしまい!

この機能はC#7で導入されました

2
Reto Messerli

私のアプローチはすることです

_(object)item == null
_

私はobject自身の等式演算子に頼っています。これは間違いありません。またはカスタム拡張メソッド(およびオーバーロード):

_public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}
_

または、より多くのケースを処理するには、次のようになります。

_public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}
_

制約は、値型のIsNullを防ぎます。今では呼び出すのと同じくらい甘い

_object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error
_

つまり、全体を通してnullをチェックする一貫した/エラーが発生しにくいスタイルが1つあります。私はまた、 _(object)item == null_はObject.ReferenceEquals(item, null) よりも非常にわずかに速いことを発見しましたが、それが重要な場合に限ります(私は現在、マイクロ化する必要がある何かに取り組んでいます-すべてを最適化してください!)。

等価性チェックの実装に関する完全なガイドを参照するには、 参照型の2つのインスタンスを比較するための「ベストプラクティス」とは何ですか? を参照してください。

1
nawfal

もっと返信する nullと比較する方法をオーバーライドする演算子 ここで重複としてリダイレクトします。

値オブジェクトをサポートするためにこれが行われている場合、私は新しい表記法が便利であると感じ、比較が行われる場所が1つだけであることを確認したいと思います。また、Object.Equals(A、B)を利用すると、ヌルチェックが簡素化されます。

これにより、==、!=、Equals、およびGetHashCodeがオーバーロードされます

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

より複雑なオブジェクトの場合は、Equalsとより豊富なGetHashCodeに比較を追加します。

0
CCondron

現代的で凝縮された構文の場合:

public static bool operator ==(Foo x, Foo y)
{
    return x is null ? y is null : x.Equals(y);
}

public static bool operator !=(Foo x, Foo y)
{
    return x is null ? !(y is null) : !x.Equals(y);
}
0
mr5

静的Equals(Object, Object)メソッド は、2つのオブジェクトobjAobjBが等しいかどうかを示します。また、値がnullであるオブジェクトが等しいかどうかをテストすることもできます。次のように、objAobjBが等しいかどうかを比較します。

  • 2つのオブジェクトが同じオブジェクト参照を表すかどうかを決定します。含まれている場合、メソッドはtrueを返します。このテストは、ReferenceEqualsメソッドを呼び出すのと同じです。さらに、objAobjBの両方がnullの場合、メソッドはtrueを返します。
  • objAまたはobjBのいずれかがnullであるかどうかを判別します。その場合、falseを返します。 2つのオブジェクトが同じオブジェクト参照を表しておらず、どちらもnullでない場合、objA.Equals(objB)を呼び出して、結果を返します。これは、objAObject.Equals(Object)メソッドをオーバーライドする場合、このオーバーライドが呼び出されることを意味します。

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}
0
Zach Posten