Domanda

Devo fare un confronto tra un oggetto e NULL. Quando l'oggetto non è NULL, lo riempio con alcuni dati.

Ecco il codice:

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

Funziona ma durante il looping e il looping a volte l'oggetto regione NON è null (posso vedere i dati al suo interno in modalità debug). Durante il debug, passo dopo passo, non va all'interno dell'istruzione IF ... Quando eseguo un Quick Watch con la seguente espressione: vedo il (region == null) restituire false, AND (region! = Null ) restituisce anche false ... perché e come?

Aggiorna

Qualcuno sottolinea che l'oggetto era == e! = sovraccarico:

    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);
    }
È stato utile?

Soluzione

L'operatore == e / o! = è sovraccarico per la classe dell'oggetto regione?

Ora che hai pubblicato il codice per i sovraccarichi:

I sovraccarichi dovrebbero probabilmente apparire come i seguenti (codice tratto dalle pubblicazioni effettuate da Jon Skeet e 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);
}

Altri suggerimenti

Questi sovraccarichi dell'operatore sono rotti.

In primo luogo, rende la vita molto più semplice se! = è implementato semplicemente chiamando == e invertendo il risultato.

In secondo luogo, prima del controllo di nullità in == ci dovrebbe essere:

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

Entrambi i sovraccarichi non sono corretti

 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);
    }

se r1 e r2 sono nulli, il primo test ( object.ReferenceEquals (r1, null) ) restituirà false, anche se r2 è anche null.

try

//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);
    }

Questo a volte può succedere quando hai più thread che lavorano con gli stessi dati. In questo caso, puoi utilizzare un lucchetto per impedire che si scambino messaggi.

Per il confronto di uguaglianza di un tipo " T " ;, sovraccarica questi metodi:

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)

Il codice di confronto specifico per il tipo deve essere eseguito in un unico punto : il metodo di interfaccia IEquatable<T> sicuro per il tipo Equals(T other). Se stai confrontando con un altro tipo (T2), implementa anche IEquatable<T2> e inserisci il codice di confronto dei campi per quel tipo in Equals (T2 altro).

Tutti i metodi e gli operatori sovraccaricati devono inoltrare l'attività di confronto di uguaglianza al metodo di istanza Equivalente al tipo principale (T altro), in modo tale da mantenere una gerarchia di dipendenze pulita e introdurre garanzie più rigorose ad ogni livello per eliminare la ridondanza e la complessità non essenziale .

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
}

Discussione:

L'implementazione precedente centralizza il confronto specifico del tipo (ovvero l'uguaglianza di campo) alla fine dell'implementazione == per il tipo. Gli operatori != e !(obj1 == obj2) hanno un'implementazione parallela ma opposta. Preferisco questo piuttosto che avere un riferimento all'altro, in modo che vi sia una chiamata di metodo aggiuntiva per quella dipendente. Se l'operatore ReferenceEquals(obj1,obj2) chiamerà semplicemente l'operatore Equals(object),Equals(T),==,!=, anziché offrire un operatore altrettanto performante, allora puoi anche usare <=> ed evitare la chiamata di metodo aggiuntiva. Il confronto con il sé è escluso dall'operatore uguale e dalle <=> implementazioni, perché può introdurre 1. sovraccarico non necessario in alcuni casi e / o 2. prestazioni incoerenti a seconda della frequenza con cui un'istanza viene confrontata con se stessa rispetto a altre istanze.

Un'alternativa che non mi piace, ma che dovrei menzionare, è quella di invertire questa configurazione, centralizzando invece il codice di uguaglianza di tipo specifico nell'operatore di uguaglianza e facendo dipendere i metodi Equals da quello. Si potrebbe quindi usare la scorciatoia di <=> per verificare l'uguaglianza di riferimento e l'uguaglianza nulla contemporaneamente come Philip ha menzionato in un post precedente, ma quell'idea è fuorviante. Sembra che tu stia uccidendo due piccioni con una fava, ma in realtà stai creando più lavoro - dopo aver determinato che gli oggetti non sono né nulli né della stessa istanza, dovrai inoltre, ANCORA, verificare se ogni istanza è zero. Nella mia implementazione, verifichi che ogni singola istanza sia nulla esattamente una volta. Quando viene chiamato il metodo dell'istanza Equals, è già escluso che il primo oggetto confrontato sia nullo, quindi tutto ciò che resta da fare è verificare se l'altro è nullo. Quindi dopo al massimo due confronti, passiamo direttamente al controllo del campo, indipendentemente dal metodo che utilizziamo (<=>). Inoltre, come ho già detto, se stai confrontando davvero e ti opponi a se stesso la maggior parte delle volte, allora potresti aggiungere quel controllo nel metodo Equals appena prima di immergerti nei confronti del campo. Il punto in cui è stato aggiunto per ultimo è che è ancora possibile mantenere la gerarchia di flusso / dipendenza senza introdurre un controllo ridondante / inutile ad ogni livello.

Quindi questi controlli qui non sono corretti:

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

C'è un'altra possibilità che devi fare clic sull'icona di aggiornamento accanto al parametro che stai guardando. VS prova a tenere il passo con le prestazioni senza valutare ogni istruzione / parametro. Dai un'occhiata per assicurarti, prima di iniziare a modificare luoghi non pertinenti.

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

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top