Почему C# позволяет Вам 'бросать пустой указатель'?

При написании некоторого особенно сложного кода обработки исключений кто-то спросил, разве Вы не должны удостоверяться, что Ваш объект исключения не является пустым? И я сказал, конечно, не, но тогда решил попробовать его. По-видимому, можно бросить пустой указатель, но он все еще превращен в исключение где-нибудь.

Почему это позволяется?

throw null;

В этом отрывке, к счастью 'исключая' не является пустым, но это могло когда-либо быть?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}
76
задан quip 3 February 2010 в 21:54
поделиться

6 ответов

Потому что спецификация языка ожидает выражения типа System.Exception (следовательно, null является допустимым в этом контексте) и не ограничивает это выражение ненулевым значением. В общем, невозможно определить, является ли значение этого выражения нулевым или нет. Это должно решить проблему остановки. Среде выполнения все равно придется иметь дело со случаем null . См .:

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 

Они, конечно, могли бы сделать конкретный случай выброса литерала null недействительным, но это не сильно помогло бы, так зачем тратить пространство спецификации и уменьшать согласованность ради небольшой выгоды?

Заявление об ограничении ответственности (до того, как меня ударит Эрик Липперт): Это мое собственное предположение о причинах этого дизайнерского решения.Конечно, я не был на совещании по проектированию;)


Ответ на ваш второй вопрос, может ли переменная выражения, пойманная в предложении catch, когда-либо иметь значение NULL: хотя в спецификации C # ничего не говорится о том, могут ли другие языки вызывать исключение null , которое будет распространяться, оно действительно определяет способ распространения исключений:

Пункты catch, если таковые имеются, проверяются в порядке появления, чтобы найти подходящий обработчик исключения. Первое предложение catch , которое определяет тип исключения или базовый тип типа исключения , считается совпадением. Общее предложение catch считается подходящим для любого типа исключения. [...]

Для null жирным шрифтом утверждение является ложным. Итак, хотя чисто на основании того, что говорится в спецификации C #, мы не можем сказать, что базовая среда выполнения никогда не будет генерировать null, мы можем быть уверены, что даже в этом случае это будет обрабатываться только общим предложение catch {} .

Для реализации C # в CLI мы можем обратиться к спецификации ECMA 335. Этот документ определяет все исключения, которые CLI генерирует внутренне (ни одно из которых не является null ), и упоминает, что определенные пользователем объекты исключений генерируются инструкцией throw . Описание этой инструкции практически идентично инструкции C # throw (за исключением того, что она не ограничивает тип объекта System.Exception ):

Описание:

Инструкция throw создает объект исключения (тип O ) в стеке и очищает стек.Подробные сведения о механизме исключений см. В Разделе I.
[Примечание: CLI разрешает создание любого объекта, но CLS описывает конкретный класс исключения, который должен использоваться для взаимодействия языков. конец примечания]

Исключения:

System.NullReferenceException выдается, если obj имеет значение null .

Корректность:

Правильный CIL гарантирует, что объект всегда либо null , либо ссылка на объект (т. Е. Типа O ).

Я считаю, что этого достаточно, чтобы сделать вывод, что пойманные исключения никогда не нулевые .

87
ответ дан 24 November 2019 в 11:19
поделиться

Взято из здесь :

Если вы используете это выражение в вашем C# код, который он бросит NullReferenceException. То есть потому что для выброса необходимо объект типа Исключение как единственный параметр. Но именно этот объект ноль в моем примере.

4
ответ дан 24 November 2019 в 11:19
поделиться

Я думаю, что, возможно, вы не можете -- когда вы пытаетесь бросить ноль, он не может, поэтому он делает то, что должен в случае ошибки, то есть бросает исключение по нулевой ссылке. Таким образом, вы на самом деле не бросаете ноль, вы не можете бросить ноль, что приводит к бросанию.

2
ответ дан 24 November 2019 в 11:19
поделиться

По-видимому, вы можете выбросить null, но это все равно где-то превращается в исключение.

Попытка выбросить объект null приводит к (совершенно не связанной) исключительной ситуации с нулевой ссылкой.

Спросить, почему вам разрешено бросать null , все равно что спросить, почему вам разрешено это делать:

object o = null;
o.ToString();
26
ответ дан 24 November 2019 в 11:19
поделиться

Попытка ответить «… слава богу, ex не является нулевым, но может ли оно когда-либо быть?»:

Поскольку мы, возможно, не можем создавать исключения имеет значение null, предложению catch также никогда не придется перехватывать исключение с нулевым значением. Таким образом, ex никогда не может быть нулевым.

Теперь я вижу, что этот вопрос фактически уже задавался .

2
ответ дан 24 November 2019 в 11:19
поделиться

Помните, что исключение включает в себя подробную информацию о том, куда выбрасывается исключение. Видя, что конструктор понятия не имеет, куда бросать, тогда имеет смысл только то, что метод броска впрыскивает эти детали в объект в точке, в которой бросают. Другими словами, CLR пытается ввести данные в ноль, что инициирует NullReferenceException.

Не уверен, что это именно то, что происходит, но это объясняет явление.

Предположив, что это правда (и я не могу придумать лучшего способа получить ex, чем бросить ноль;), это будет означать, что ex не может быть нулем.

1
ответ дан 24 November 2019 в 11:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: