Devo sobrecarga == Operador?
-
08-07-2019 - |
Pergunta
Como é que o operador ==
funcionar realmente em C #? Se usado para comparar os objetos da classe A , vai tentar igualar todos A 's propriedades, ou vai procurar ponteiros para o mesmo local de memória (ou talvez outra coisa)?
Vamos criar um exemplo hipotético. Eu estou escrevendo um aplicativo que utiliza a API do Twitter, e tem um Tweet classe, que tem todas as propriedades de um único tweet: texto, remetente, data e hora, fonte, etc. Se eu quiser comparar objetos da classe Tweet de equivalência, eu só posso usar:
Tweet a, b;
if (a == b)
{
//do something...
}
Will que verificação de equivalência de todas as propriedades do Tweet de classe entre a e b / p>
Se não, seria a abordagem correta ser sobrecarregar o operador ==
para verificar explicitamente a equivalência de todos os campos?
UPDATE: A partir das duas primeiras respostas, estou certo em assumir:
- Se o operador
==
ou Igual método não é sobrecarregado para uma classe, o operador==
para o objeto classe é usada. - O operador
==
para os objeto cheques de classe para a igualdade no local de memória. - Eu tenho que sobrecarregar o operador
==
ou o Igual método para realizar esta tarefa. - Na sobrecarga, eu tenho que verificar se há equivalência nas propriedades manualmente, então não há nenhuma maneira de fazê-lo semi-automaticamente, digamos, em um loop , certo?
update # 2: Yuriy fez um comentário que é possível fazer verificação de equivalência em propriedades no operador ==
com reflexão . Como isso pode ser feito? Você poderia me dar algum código de exemplo? Obrigado!
Solução
MSDN tem uma boa exemplo de como fazê-lo:
public override bool Equals(object o)
{
try
{
return (bool) (this == (DBBool) o);
}
catch
{
return false;
}
}
Então você sobrecarregar o == e =:
// Equality operator. Returns dbNull if either operand is dbNull,
// otherwise returns dbTrue or dbFalse:
public static DBBool operator ==(DBBool x, DBBool y)
{
if (x.value == 0 || y.value == 0) return dbNull;
return x.value == y.value? dbTrue: dbFalse;
}
// Inequality operator. Returns dbNull if either operand is
// dbNull, otherwise returns dbTrue or dbFalse:
public static DBBool operator !=(DBBool x, DBBool y)
{
if (x.value == 0 || y.value == 0) return dbNull;
return x.value != y.value? dbTrue: dbFalse;
}
E não se esqueça de sobrecarregar o método GetHash.
Editar:
Eu escrevi o seguinte exemplo rápida para utilizar o reflexo em um comparar. Isso teria que ser muito mais abrangente, eu poderia tentar fazer um blog em que se as pessoas querem que eu:
public class TestEquals
{
private int _x;
public TestEquals(int x)
{
this._x = x;
}
public override bool Equals(object obj)
{
TestEquals te = (TestEquals)obj;
if (te == null) return false;
foreach (var field in typeof(TestEquals)
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (!field.GetValue(this).Equals(field.GetValue(te)))
return false;
}
return true;
}
}
Outras dicas
Para tipos de referência, as implementações padrão de tanto o operador ==
eo método Equals()
simplesmente verificar se os dois objetos têm a mesma referência, e são, portanto, a mesma instância.
Se você quiser verificar o conteúdo de dois objetos diferentes são iguais, então você deve escrever o código para fazê-lo sozinho, de uma forma ou de outra. Seria possível fazer com reflexão (a MbUnit framework de teste faz algo nesse sentido), mas com um pesado penalidade de desempenho e uma boa chance de que ele não faria bem o que você espera de qualquer maneira, e você deve implementar ==
ou Equals
e GetHashCode
à mão.
A abordagem adequada é a sobrecarga do método da classe Tweet igual, além de o operador ==, como descrito aqui .
Will que cheque de equivalência de todas as propriedades da classe Tweet entre um e b?
Não
Se não, seria a abordagem correta ser sobrecarregar o operador == para verificar explicitamente a equivalência de todos os campos?
Você pode sobrecarregar o == do operador, ou sobrecarregar o Igual função.
Editar
@Yuriy deu um bom exemplo para compating todas as variáveis ??não públicos. Desde que eu também escreveu um exemplo, aqui está (o meu compara propriedades)
class TwitterItem
{
private string myValue = "default value";
public string Value1
{
get { return myValue; }
set { myValue = value; }
}
public string Value2
{
get { return myValue; }
set { myValue = value; }
}
public string Value3
{
get { return myValue; }
set { myValue = value; }
}
public override bool Equals(object obj)
{
if (base.Equals(obj)) return true;
Type type = typeof(TwitterItem);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (false == property.GetValue(this, null).Equals(property.GetValue(obj, null)))
return false;
}
return true;
}
}
Você pode comparar as propriedades usando a reflexão:
var a = new Entity() { Name = "test", ID = "1" };
var b = new Entity() { Name = "test", ID = "1" };
var c = new Entity() { Name = "test", ID = "2" };
System.Diagnostics.Debug.WriteLine(a.Equals(b));//Returns true
System.Diagnostics.Debug.WriteLine(a.Equals(c));//Returns false
public class Entity
{
public string Name { get; set; }
public string ID { get; set; }
public override bool Equals(object obj)
{
var t = obj.GetType();
foreach (var p in t.GetProperties())
{
if (t.GetProperty(p.Name).GetValue(obj, null) != t.GetProperty(p.Name).GetValue(this, null))
return false;
}
return true;
}
}