Como posso verificar para valores nulos em uma '==' a sobrecarga do operador sem recursão infinita?
-
09-06-2019 - |
Pergunta
A seguir fará com que a recursividade infinita sobre o operador == de sobrecarga do método
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);
}
Como posso verificar nulos?
Solução
Utilização 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);
}
Outras dicas
O elenco objeto no método de sobrecarga:
public static bool operator ==(Foo foo1, Foo foo2) {
if ((object) foo1 == null) return (object) foo2 == null;
return foo1.Equals(foo2);
}
Utilização ReferenceEquals
.Do Fóruns do 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;
}
Tente Object.ReferenceEquals(foo1, null)
De qualquer maneira, eu não recomendaria a sobrecarga do ==
operador;ele deve ser usado para a comparação de referências, e usar Equals
para a "semântica" comparações.
Se eu tiver overrided bool Equals(object obj)
e eu quero que o operador ==
e Foo.Equals(object obj)
para retornar a mesma resposta, eu geralmente implementar o !=
operador de como este:
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);
}
O operador ==
irá, em seguida, depois de fazer todos os cheques nulos para mim acabam chamando foo1.Equals(foo2)
que eu assumi para fazer o verifique se os dois são iguais.
Se você estiver usando C# 7 ou mais tarde, você pode usar a constante nulo correspondência de padrão:
public static bool operator==(Foo foo1, Foo foo2)
{
if (foo1 is null)
return foo2 is null;
return foo1.Equals(foo2);
}
Isso dá a você um pouco mais puro do código do que o objecto de chamada.ReferenceEquals(foo1, null)
Minha abordagem é a de fazer
(object)item == null
sobre o que eu estou confiando em object
'do próprio operador de igualdade que não pode dar errado.Ou uma extensão personalizada método (e uma sobrecarga):
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;
}
ou para lidar com mais casos, pode ser:
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null || obj == DBNull.Value;
}
A restrição impede IsNull
em tipos de valor.Agora a sua doce como chamar
object obj = new object();
Guid? guid = null;
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error
o que significa que eu tenho um consistente/não-passível de erro estilo de verificar nulos todo.Eu também tenho encontrado (object)item == null
é muito, muito, muito ligeiramente mais rápido do que Object.ReferenceEquals(item, null)
, mas só se importa (atualmente estou trabalhando em algo que eu mandei para micro-otimizar tudo!).
Para ver um guia completo sobre a implementação da igualdade verificações, consulte O que é a "Melhor Prática" Para a Comparação de Duas Instâncias de um Tipo de Referência?
Estática Equals(Object, Object)
método indica se dois objetos, objA
e objB
, são iguais.Ele também permite que você teste os objectos cujo valor é null
para a igualdade.Ele compara objA
e objB
para a igualdade da seguinte maneira:
- Ele determina se os dois objectos que representam o mesmo objeto de referência.Se o fizerem, o método retorna
true
.Este teste é equivalente a chamar aReferenceEquals
o método.Além disso, se ambos osobjA
eobjB
sãonull
, o método retornatrue
. - Ele determina se quer
objA
ouobjB
énull
.Se assim for, ele retornafalse
.Se os dois objectos não representam o mesmo objeto de referência e nem énull
, ele chamaobjA.Equals(objB)
e retorna o resultado.Isso significa que, seobjA
substitui aObject.Equals(Object)
método, esta substituição é chamado.
.
public static bool operator ==(Foo objA, Foo objB) {
return Object.Equals(objA, objB);
}
respondendo mais substituindo o operador como para comparar null que redireciona aqui como uma duplicata.
Nos casos em que isso está sendo feito para suportar Objectos de Valor, acho que a nova notação para a calhar, e gostaria de garantir que só existe um lugar onde a comparação é feita.Também aproveitando o Objeto.É igual a(A, B) simplifica o nulo verifica.
Isto irá sobrecarregar ==, !=, É igual a, 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();
Para mais complicado objetos de adicionar outras comparações em pares e uma rica GetHashCode.
Há, na verdade, uma forma mais simples de verificar contra null
neste caso:
if (foo is null)
Que é isso!
Esta funcionalidade foi introduzida no C# 7
Um erro comum na sobrecarga do operador == é para usar
(a == b)
,(a ==null)
, ou(b == null)
para verificar igualdade de referência.Este, em vez resultados uma chamada para o operador sobrecarregado ==, causando uminfinite loop
.UtilizaçãoReferenceEquals
o elenco do tipo de Objeto, para evitar o loop.
confira este
// 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;
}
referência Diretrizes para a Sobrecarga é Igual a() e o Operador ==
Você pode tentar usar uma propriedade de objeto e pegar a resultante de NullReferenceException.Se a propriedade tentar é herdada ou substituído, de Objecto e, em seguida, isso funciona para qualquer 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;
}