web-dev-qa-db-ja.com

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

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

ここにコードがあります:

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

これは機能していますが、ループしてループするときに、リージョンオブジェクトがnullではありません(デバッグモードでその中にデータを表示できます)。デバッグ時のステップバイステップでは、IFステートメントの内部に移動しません...次の式でクイックウォッチを実行すると、(region == null)が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);
    }
17

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

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

オーバーロードはおそらく次のようになります( 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);
}
29
Michael Burr

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

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

次に、nullityが==でチェックする前に、次のものが必要です。

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

両方のオーバーロードが正しくありません

 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の場合、r2もnullであっても、最初のテスト(object.ReferenceEquals(r1、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);
    }
7
Philip Rieck

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

3
skb

タイプ「T」の等価比較のために、これらのメソッドをオーバーロードします。

_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
}
_

ディスカッション:

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

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

2
Triynko

したがって、これらのチェックが正しくないのは次のとおりです。

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

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

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

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;
0
fernando