Come faccio a controllare null in un '==' operatore di sovraccarico senza ricorsione infinita?
-
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?
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 ilReferenceEquals
metodo.Inoltre, se entrambiobjA
eobjB
sononull
, il metodo restituiscetrue
. - Determina se sia
objA
oobjB
ènull
.Se è così, restituiscefalse
.Se i due oggetti non rappresentano lo stesso oggetto di riferimento e non ènull
, chiamaobjA.Equals(objB)
e restituisce il risultato.Questo significa che seobjA
sostituisce ilObject.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 uninfinite loop
.UtilizzareReferenceEquals
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;
}