C#オブジェクトはnullではありませんが、(myObject!= null)まだfalseを返します

StackOverflow https://stackoverflow.com/questions/155458

  •  03-07-2019
  •  | 
  •  

質問

オブジェクトとNULLを比較する必要があります。オブジェクトがNULLでない場合、データを入力します。

コードは次のとおりです:

 if (region != null)
 {
  ....
 }

これは動作しますが、ループとループのときにリージョンオブジェクトがnullではありません(デバッグモードでその中のデータを見ることができます)。デバッグ時の段階的な手順では、IFステートメントの内部には入りません...次の式でクイックウォッチを実行すると、(region == null)return false、AND(region!= null )falseも返します... 理由と方法

更新

オブジェクトが==および!=過負荷であったと指摘する人がいます:

    public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }


    public static bool operator !=(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }
        return (r1.Cmr.CompareTo(r2.Cmr) != 0 || r1.Id != r2.Id);
    }
役に立ちましたか?

解決

リージョンオブジェクトのクラスに対して==および/または!=演算子がオーバーロードされていますか?

これでオーバーロードのコードを投稿しました:

オーバーロードは、おそらく次のようになります( Jon Skeet および Philip Rieck ):

public static bool operator ==(Region r1, Region r2)
{
    if (object.ReferenceEquals( r1, r2)) {
        // handles if both are null as well as object identity
        return true;
    }

    if ((object)r1 == null || (object)r2 == null)
    {
       return false;
    }        

    return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}

public static bool operator !=(Region r1, Region r2)
{
    return !(r1 == r2);
}

他のヒント

これらの演算子のオーバーロードは壊れています。

まず、==を呼び出して結果を反転するだけで!=が実装されていると、作業がずっと楽になります。

第二に、==で無効性がチェックされる前に、次のようになります。

if (object.ReferenceEquals(r1, r2))
{
    return true;
}

両方のオーバーロードが間違っています

 public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

r1およびr2がnullの場合、最初のテスト( object.ReferenceEquals(r1、null))は、r2もnullであってもfalseを返します。

試用

//ifs expanded a bit for readability
 public static bool operator ==(Region r1, Region r2)
    {
        if( (object)r1 == null && (object)r2 == null)
        {
           return true;
        }
        if( (object)r1 == null || (object)r2 == null)
        {
           return false;
        }        
        //btw - a quick shortcut here is also object.ReferenceEquals(r1, r2)

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

これは、同じデータを処理する複数のスレッドがある場合に発生することがあります。この場合、ロックを使用して、お互いに干渉しないようにすることができます。

型<!> quot; T <!> quot;の等値比較のために、これらのメソッドをオーバーロードします:

int GetHashCode() //Overrides Object.GetHashCode
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to
static bool operator ==(T x, T y)
static bool operator !=(T x, T y)

タイプ固有の比較コードは1か所で実行する必要があります:タイプセーフなIEquatable<T>インターフェイスメソッドEquals(T other)。 別の型(T2)と比較する場合は、IEquatable<T2>も実装し、その型のフィールド比較コードをEquals(T2 other)に入れます。

すべてのオーバーロードされたメソッドと演算子は、等価比較タスクをメインのタイプセーフなEquals(T other)インスタンスメソッドに転送する必要があります。これにより、クリーンな依存関係階層が維持され、各レベルで厳格な保証が導入されて、冗長性と不要な複雑さが排除されます。

bool Equals(object other)
{
    if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement
        return Equals( (T)other) ); //forward to IEquatable<T> implementation
    return false; //other is null or cannot be compared to this instance; therefore it is not equal
}

bool Equals(T other)
{
    if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return false;
    //if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check
        //return true;
    return field1.Equals( other.field1 ) &&
           field2.Equals( other.field2 ); //compare type fields to determine equality
}

public static bool operator ==( T x, T y )
{
    if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return false; //x was null, y is not null
    return true; //both null
}

public static bool operator !=( T x, T y )
{
    if ((object)x != null)
        return !x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return true; //x was null, y is not null
    return false; //both null
}

ディスカッション:

前述の実装は、型の==実装の終わりに対する型固有の(つまり、フィールドの等価性)比較を集中化します。 !=演算子と!(obj1 == obj2)演算子には、並列ですが反対の実装があります。私は、一方が他方を参照するよりも、これを使用して、依存するメソッドの追加のメソッド呼び出しがあるようにします。 ReferenceEquals(obj1,obj2)演算子が、同等に機能する演算子を提供するのではなく、単にEquals(object),Equals(T),==,!=演算子を呼び出す場合は、<=>を使用して余分なメソッド呼び出しを回避することもできます。 自己比較は、等号演算子および<=>実装から除外されます。これは、1。場合によっては不要なオーバーヘッド、および/または2.インスタンスがそれ自体と比較される頻度に応じて一貫性のないパフォーマンスをもたらす可能性があるためです。他のインスタンス。

好きではないが言及すべき代替案は、このセットアップを逆にして、代わりに等値演算子で型固有の等値コードを集中させ、Equalsメソッドをそれに依存させることです。フィリップが以前の投稿で言及したように、<=>のショートカットを使用して参照の等価性とnullの等価性を同時にチェックできますが、その考えは誤解を招きます。 1石で2羽の鳥を殺しているように見えますが、実際にはより多くの作業を作成しています-オブジェクトがヌルでも同じインスタンスでもないことを確認したら、さらに各インスタンスをチェックする必要があります無効です。私の実装では、単一のインスタンスがnullであるかどうかを一度だけ確認します。 Equalsインスタンスメソッドが呼び出されるまでに、比較される最初のオブジェクトがnullであることが既に除外されているため、残りの作業は、もう一方がnullであるかどうかを確認することだけです。そのため、使用するメソッド(<=>)に関係なく、最大2回の比較後、フィールドチェックに直接ジャンプします。また、前述したように、ほとんどの場合、自分自身と実際に比較して反対する場合は、フィールド比較に飛び込む直前にそのチェックをEqualsメソッドに追加できます。最後に追加するポイントは、すべてのレベルで冗長/不要なチェックを導入することなく、フロー/依存関係の階層を維持できることです。

これらのチェックが正しくないということです:

public static bool operator !=(Region r1, Region r2)
{
    if (object.ReferenceEquals(r1, null))
    {
        return false;
    }
    if (object.ReferenceEquals(r2, null))
    {
        return false;
    }
...

監視しているパラメーターの横にある更新アイコンをクリックする必要があるという別の可能性があります。 VSは、すべてのステートメント/パラメーターを評価せずに、パフォーマンスに遅れないようにします。関係のない場所に変更を加える前に、確認してください。

bool comp;
if (object.IsNullOrEmpty(r1))
{
    comp = false;
}

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top