Почему String.Equals(Object obj) проверяет, является ли это == нулевым?
Возможный дубликат:
Зачем проверять это!= Ноль?
// Determines whether two strings match.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(Object obj)
{
//this is necessary to guard against reverse-pinvokes and
//other callers who do not use the callvirt instruction
if (this == null)
throw new NullReferenceException();
String str = obj as String;
if (str == null)
return false;
if (Object.ReferenceEquals(this, obj))
return true;
return EqualsHelper(this, str);
}
Часть, которую я не понимаю, это то, что она проверяет текущий экземпляр, this
против нуля. Комментарий немного сбивает с толку, поэтому мне было интересно, что на самом деле означает этот комментарий?
Может ли кто-нибудь привести пример того, как это могло сломаться, если бы этой проверки не было, и означает ли это, что я должен также разместить эту проверку в своих классах?
2 ответа
Эта проверка служит защитой от нативного кода, который может вызывать функцию с нулевым значением. this
указатель. Это не может произойти в C#, поэтому вам не нужно помещать подобные элементы в ваш код. Вполне возможно, что String
класс был написан до того, как C# был завершен, и автор, возможно, подумал, что важно защититься от пустых значений, или, возможно, это просто String
методы из нативного кода и других мест, которые облегчают вызов методов при нулевом.
Обратите внимание, что даже если вам удастся позвонить с нулевым this
и у вас нет охраны, все, что произойдет, это то, что исключение будет немного другим. Это может быть другое исключение, и его может вызвать другой участник, но в противном случае это вряд ли что-то изменит.
Другими словами, если нулевой проверки не было, EqualsHelper
(или один из его вызываемых абонентов) выдает исключение, а не Equals
, Поскольку желательно скрыть внутреннюю часть видимой пользователю функции, имеет смысл поставить проверку в самом начале.
- Такие языки, как C# и VB.NET, используют callvirt для создания NullReference перед вводом метода экземпляра (this == null), проверки не нужны.
- Такие языки, как F# и Managed C++ (в большинстве случаев) используют инструкцию call, где вы можете получить метод экземпляра с нулевым указателем this. (это == ноль) имеет эффект.
Добавленная проверка нуля предназначена не только для последних языков, но и для помощи в отладке для выброса в месте, где происходит ошибка (вызов метода экземпляра нулевого объекта). Если этого не было, вы можете вызывать любой метод внутри класса без каких-либо ошибок, если это никогда не разыменовывается (обращается к переменным-членам). Это может зайти так далеко, что для вашего нулевого объекта сработало несколько вызовов методов, и внезапно вы получите исключение нулевой ссылки (метод, к которому обращались данные экземпляра).
Если вы посмотрите на проверки внутри классов.NET, то станет ясно, что такие элементы защиты есть только в некоторых известных классах, таких как string. Другие методы, такие как IndexOf, не защищают от этого. Это противоречиво, но я думаю, что снижение производительности для таких двойных нулевых проверок не стоило усилий, потому что большинство пользователей BCL - это языки, которые используют инструкцию callvirt, где вторая нулевая проверка не помогает.