Почему Assert.AreEqual() бросает объект перед сравнением?
Я пишу некоторые модульные тесты, и следующее утверждение не выполняется:
Assert.AreEqual(expected.Episode, actual.Episode);
Если я назову это вместо этого, он преуспеет:
Assert.IsTrue(expected.Episode.Equals(actual.Episode));
Я предположил, что Assert.AreEqual()
в конечном итоге вызывает метод Equals()
для типа, который он задает, в этом случае Episode.Equals()
.
Однако под обложками Microsoft.VisualStudio.TestTools.UnitTesting.Assert нашел следующий код (декомпилированный ReSharper):
public static void AreEqual<T>(T expected, T actual, string message, params object[] parameters)
{
if (object.Equals((object)expected, (object)actual))
return;
Assert.HandleFail...
}
Это означает, что метод AreEqual()
отличает как expected
, так и actual
до object
для принудительного использования базового метода Equals()
, а не перегрузки, которую я написал в Episode
класс. Базовый метод будет просто проверять, совпадают ли ссылки, какими они не являются.
У меня есть два вопроса:
- Мое объяснение действительно правильно, или я что-то пропустил?
- Почему инфраструктура хочет принудительно использовать object.Equals(), а не перегрузку этого метода?
Если это актуально, вот мой метод:
public bool Equals(Episode other)
{
return Number == other.Number &&
CaseNote.Equals(other.CaseNote) &&
Patient.Equals(other.Patient);
}
Ответы
Ответ 1
Использует object.Equals(object,object)
, который имеет дело с такими вещами, как:
- являются ли они одной и той же ссылкой?
- является либо ссылкой, либо ссылкой
null
?
а затем продолжает использовать x.Equals(y)
после того, как он обработал эти вещи. Он должен передать их object
, потому что это то, что принимает object.Equals(object,object)
. Литье в object
также позволяет избежать некоторых осложнений с помощью Nullable<T>
(потому что a T?
помещается либо в null
, либо в стандартную коробку T
).
Однако он также может быть реализован как:
if (EqualityComparer<T>.Default.Equals(expected,actual))
return;
который обрабатывает Nullable<T>
, IEquatable<T>
, struct
vs class
и несколько других сценариев без бокса.
Но: текущая реализация выполняет задание, а случайный ящик - это не конец света (и: бокс даже не проблема, если ваш тип class
).
Ответ 2
В вашем коде вам также необходимо переопределить Equals(object other)
(и также необходимо переопределить GetHashCode).
Просто добавьте это в свой код
public bool Equals(Episode other)
{
return Number == other.Number &&
CaseNote.Equals(other.CaseNote) &&
Patient.Equals(other.Patient);
}
public override bool Equals(object other)
{
Episode castOther = other as Episode;
if(castOther == null)
return false;
return this.Equals(castOther);
}
public override int GetHashCode()
{
//TODO: Implement using the members you used in "Equals(Episode other)"
throw new NotImplmentedExecption();
}
Помните о GetHashCode, если два объекта равны, они должны также возвращать одинаковые хэш-коды. Вот краткая диаграмма, которая поможет визуализировать.
![enter image description here]()
Вы можете проверить CaseNote
и Patient
на аналогичные проблемы.