Come faccio a controllare null in un '==' operatore di sovraccarico senza ricorsione infinita?

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

  •  09-06-2019
  •  | 
  •  

Domanda

Il seguente, una ricorsione infinita su = operatore= metodo di overload

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

Come faccio a controllare i valori null?

È stato utile?

Soluzione

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

Altri suggerimenti

Cast per oggetto il metodo di overload:

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

Utilizzare ReferenceEquals.Dal Forum di 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;
}

Provare Object.ReferenceEquals(foo1, null)

Comunque, mi raccomando di non sovraccaricare il ==operatore;dovrebbe essere utilizzato per confrontare i riferimenti, e l'uso Equals per la "semantica" di confronto.

Se ho overrided bool Equals(object obj) e voglio l'operatore == e Foo.Equals(object obj) per restituire la stessa risposta, io di solito implementare il != operatore di simile a questo:

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

L'operatore == poi dopo aver fatto tutti i controlli nulli per me finiscono per chiamare foo1.Equals(foo2) che ho sovrascritto a fare il controllo se i due sono uguali.

Se si utilizza C# 7 o versione successiva, è possibile utilizzare la costante null pattern matching:

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

Questo ti dà leggermente più preciso codice di un oggetto chiamante.ReferenceEquals(pippo1, null),

Il mio approccio è quello di fare

(object)item == null

su cui sto contando su object's proprio operatore di uguaglianza che non si può sbagliare.O un'estensione personalizzata metodo (sovraccarico):

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

o per gestire più casi, può essere:

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

Il vincolo impedisce IsNull sui tipi di valore.Ora, con la sua dolce come la chiamata

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

il che significa che ho una coerente/non-error-prone stile di verifica per i valori null in tutto.Ho anche trovato (object)item == null è molto molto molto leggermente più veloce rispetto Object.ReferenceEquals(item, null), ma solo se la materia (attualmente sono al lavoro su qualcosa di cui non ho la micro-ottimizzare il tutto!!).

Per vedere una guida completa su come attuare la parità di controlli, per vedere Che cosa è una "Best Practice" Per il Confronto di Due Istanze di un Tipo di Riferimento?

Statico Equals(Object, Object) metodo indica se due oggetti, objA e objB, sono uguali.Consente, inoltre, di verificare gli oggetti il cui valore è null per la parità.Confronta objA e objB per l'uguaglianza come segue:

  • Determina se i due oggetti rappresentano lo stesso oggetto di riferimento.Se lo fanno, il metodo restituisce true.Questo test è equivalente a chiamare il ReferenceEquals metodo.Inoltre, se entrambi objA e objB sono null, il metodo restituisce true.
  • Determina se sia objA o objB è null.Se è così, restituisce false.Se i due oggetti non rappresentano lo stesso oggetto di riferimento e non è null, chiama objA.Equals(objB) e restituisce il risultato.Questo significa che se objA sostituisce il Object.Equals(Object) metodo, questo annullamento è chiamato.

.

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

la risposta più override operatore come confrontare a null che reindirizza qui come un duplicato.

Nei casi In cui questo è stato fatto per supportare gli Oggetti di Valore, trovo la nuova notazione a portata di mano, e di fare in modo che non c'è un solo posto dove il confronto è fatto.Inoltre sfruttando Oggetto.È uguale a(A, B) semplifica i controlli nulli.

Questo sovraccarico ==, !=, È uguale, e 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();

Per più oggetti complicati aggiungere ulteriori confronti in pari, e una più ricca GetHashCode.

In realtà, c'è un modo più semplice di controllo contro null in questo caso:

if (foo is null)

Ecco!!!

Questa funzione è stata introdotta in C# 7

Un errore comune in overload dell'operatore == per l'uso (a == b), (a ==null), o (b == null) per verificare riferimento uguaglianza.Questo invece risultati in una chiamata per l'overload dell'operatore ==, causando un infinite loop.Utilizzare ReferenceEquals o in ghisa del tipo di Oggetto, per evitare il loop.

check out questo

// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
    return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
    return false;
}

riferimento Linee guida per il Sovraccarico di Equals() e l'Operatore ==

Si può provare a utilizzare una proprietà di un oggetto e prendere la conseguente NullReferenceException.Se la proprietà non è ereditato o sostituiti da Oggetto, quindi questo funziona per qualsiasi classe.

public static bool operator ==(Foo foo1, Foo foo2)
{
    //  check if the left parameter is null
    bool LeftNull = false;
    try { Type temp = a_left.GetType(); }
    catch { LeftNull = true; }

    //  check if the right parameter is null
    bool RightNull = false;
    try { Type temp = a_right.GetType(); }
    catch { RightNull = true; }

    //  null checking results
    if (LeftNull && RightNull) return true;
    else if (LeftNull || RightNull) return false;
    else return foo1.field1 == foo2.field2;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top