Почему C # позволяет вам «выбрасывать ноль»? - PullRequest
75 голосов
/ 04 февраля 2010

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

Почему это разрешено?

throw null;

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

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

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}

Ответы [ 7 ]

83 голосов
/ 04 февраля 2010

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

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

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

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


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

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

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

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

Описание:

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

Исключения:

System.NullReferenceException выбрасывается, если obj равно null.

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

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

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

26 голосов
/ 04 февраля 2010

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

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

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

object o = null;
o.ToString();
5 голосов
/ 28 сентября 2011

Хотя в C # может быть невозможно выбросить ноль, потому что бросок обнаружит это и превратит в исключение NullReferenceException, возможно получить ноль ... Я получаю это прямо сейчас, что вызывает мой уловкоторый не ожидал, что 'ex' будет нулевым), возникнет исключение нулевой ссылки, что приведет к смерти моего приложения (так как это был последний улов).

Итак, хотя мы не можем выбросить ноль из C #, мир преисподней может выбросить ноль, поэтому ваш самый дальний улов (исключение ex) лучше подготовить для его получения.Просто к вашему сведению.

4 голосов
/ 04 февраля 2010

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

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

2 голосов
/ 04 февраля 2010

Попытка ответить «... к счастью,« ex »не равно нулю, но могло ли это быть когда-нибудь?»:

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

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

2 голосов
/ 04 февраля 2010

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

1 голос
/ 04 февраля 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...