Должен ли я перегружать оператор ==?
-
08-07-2019 - |
Вопрос
Как ==
оператор действительно работает в C #?Если бы он использовался для сравнения объектов класса А, будет ли он пытаться сопоставить все Асвойства, или он будет искать указатели на одну и ту же ячейку памяти (или, может быть, на что-то еще)?
Давайте создадим гипотетический пример.Я пишу приложение, использующее Twitter API, и у него есть Твитнуть класс, который обладает всеми свойствами одного твита:текст, отправитель, дата и время, источник и т. д.Если я хочу сравнить объекты класса Твитнуть для эквивалентности, могу ли я просто использовать:
Tweet a, b;
if (a == b)
{
//do something...
}
Будет ли это проверка на эквивалентность всех свойств принадлежащий Твитнуть класс между а и б?
Если не, будет ли правильным подходом перегрузить ==
оператор явно проверить эквивалентность всех полей?
ОБНОВЛЯТЬ: Из первых двух ответов я прав, предполагая:
- Если
==
оператор или Равно метод не перегружен для класса, метод==
оператор по объект используется класс. - В
==
оператор по объект класс проверяет равенство ячеек памяти. - мне приходится перегружать
==
оператор или Равно метод выполнения этой задачи. - В перегрузке мне приходится вручную проверять эквивалентность свойств, поэтому нет возможности сделать это полуавтоматически, скажем, в цикле, верно?
ОБНОВЛЕНИЕ № 2: Юрий прокомментировал, что можно сделать проверку на эквивалентность свойств в файле ==
оператор с отражение.Как это может быть сделано?Не могли бы вы дать мне пример кода?Спасибо!
Решение
MSDN имеет хороший пример о том, как это сделать:
public override bool Equals(object o)
{
try
{
return (bool) (this == (DBBool) o);
}
catch
{
return false;
}
}
Затем вы перегружаете == и !=:
// 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;
}
И не забудьте перегрузить метод GetHash.
Редактировать:
Я написал следующий краткий пример использования отражения при сравнении.Это должно быть гораздо более подробно, я мог бы попробовать вести об этом блог, если люди хотят, чтобы я:
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;
}
}
Другие советы
Для ссылочных типов реализации по умолчанию как ==
оператор и Equals()
метод просто проверит, что оба объекта имеют одну и ту же ссылку и, следовательно, являются одним и тем же экземпляром.
Если вы хотите проверить, что содержимое двух разных объектов одинаково, вам придется написать код, чтобы сделать это самостоятельно, так или иначе.Можно было бы обойтись отражением ( МбЮнит тестовая среда делает что-то подобное), но с большим снижением производительности и большой вероятностью, что она все равно не будет делать то, что вы ожидали, и вам следует реализовать ==
или Equals
и GetHashCode
рукой.
Правильный подход — перегрузить метод равенства класса Tweet в дополнение к оператору ==, как описано. здесь.
Будет ли это проверять эквивалентность всех свойств класса Tweet между a и b?
Нет
Если нет, то будет ли правильным подходом перегрузить оператор == для явной проверки эквивалентности всех полей?
Вы можете либо перегрузить == оператор или перегрузить Равно функция.
Редактировать
@Yuriy дал хороший пример сравнения всех закрытых переменных.Поскольку я также написал пример, вот он (мой сравнивает свойства)
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;
}
}
Вы можете сравнить свойства, используя отражение:
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;
}
}