Почему NullReferenceException выбрасывается в переопределенный метод Object.Equals?

Я только что нашел его в dotPeek, String.cs:

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[__DynamicallyInvokable]
public override bool Equals(object obj)
{
  if (this == null)
    throw new NullReferenceException();
  string strB = obj as string;
  if (strB == null)
    return false;
  if (object.ReferenceEquals((object) this, obj))
    return true;
  if (this.Length != strB.Length)
    return false;
  else
    return string.EqualsHelper(this, strB);
}

Во второй строке выдается исключение NullReferenceException, если это == null. Так как же можно вызвать метод нулевого объекта?

MSDN говорит: обратите внимание, что приложения генерируют исключение ArgumentNullException, а не исключение NullReferenceException, которое обсуждается здесь.

Следующие инструкции Microsoft на промежуточном языке (MSIL) генерируют исключение NullReferenceException:

callvirt
cpblk
cpobj
initblk
ldelem.<type>
ldelema
ldfld
ldflda
ldind.<type>
ldlen
stelem.<type>
stfld
stind.<type>
throw
unbox

Если я получаю это, исключение выдается перед входом в тело метода. Правильно? Так что же нужно, чтобы вызвать исключение NullReferenceException из метода? Есть ли __DynamicallyInvokableAttribute заставить метод вызываться в обход каких-либо проверок? Или что-то другое?

Благодарю.

1 ответ

Решение

C# использует callvirt, где вы получаете NullReferenceException до ввода нулевого объекта. Но так как BCL создан для множества языков, они защищали от нулевых объектов в некоторых центральных частях (таких как строка), которые действительно используют инструкцию вызова.

Управляемый C++ является наиболее заметным пользователем инструкции вызова.

Это было сделано, чтобы немного помочь в отладке (насколько я знаю), но это совсем не согласовано в BCL.

Другие вопросы по тегам