При написании очень сложного кода обработки исключений кто-то спросил, не нужно ли вам убедиться, что ваш объект исключения не равен нулю? И я сказал, конечно, нет, но потом решил попробовать. По-видимому, вы можете выбросить null, но это все равно где-то превращается в исключение.
Почему это разрешено?
throw null;
К счастью, в этом фрагменте ex не имеет значения null, но может ли это когда-нибудь быть?
try
{
throw null;
}
catch (Exception ex)
{
//can ex ever be null?
//thankfully, it isn't null, but is
//ex is System.NullReferenceException
}
c#
exception-handling
шутка
источник
источник
throw
оператора, цель которого в первую очередь генерировать исключение, предупреждение не добавляет большого значения.Ответы:
Поскольку спецификация языка ожидает там выражения типа
System.Exception
(следовательно,null
является допустимым в этом контексте) и не ограничивает это выражение ненулевым значением. В общем, невозможно определить, равно ли значение этого выраженияnull
. Это должно было бы решить проблему остановки. Среда выполнения вnull
любом случае должна будет заняться этим делом. Видеть:Exception ex = null; if (conditionThatDependsOnSomeInput) ex = new Exception(); throw ex;
Они, конечно, могли бы сделать конкретный случай исключения
null
буквального недопустимым, но это не сильно помогло бы, так зачем тратить пространство спецификации и уменьшать согласованность с небольшой выгодой?Заявление об ограничении ответственности (до того, как меня ударит Эрик Липперт): это мое собственное предположение о причинах этого дизайнерского решения. Я, конечно, не был на дизайнерской встрече;)
Ответ на ваш второй вопрос, может ли переменная выражения, пойманная в предложении catch, когда-либо иметь значение NULL: хотя спецификация C #
null
ничего не говорит о том, могут ли другие языки вызывать распространение исключения, она определяет способ распространения исключений:Ибо
null
жирное заявление неверно. Итак, хотя чисто на основе того, что говорится в спецификации C #, мы не можем сказать, что базовая среда выполнения никогда не будет генерировать null, мы можем быть уверены, что даже в этом случае это будет обрабатываться только общимcatch {}
предложением.Для реализации C # в CLI мы можем обратиться к спецификации ECMA 335. Этот документ определяет все исключения, которые CLI генерирует внутренне (ни одно из которых не является
null
), и упоминает, что определенные пользователем объекты исключения генерируютсяthrow
инструкцией. Описание этой инструкции практически идентично инструкции C #throw
(за исключением того, что она не ограничивает тип объектаSystem.Exception
):Я считаю, что этого достаточно, чтобы сделать вывод, что пойманных исключений никогда не бывает
null
.источник
throw null;
.catch { }
предложения.throw
аргумент, аргумент которого может быть нулевым значением, это не означает, чтоthrow null
это должно быть законным. Компилятор может настоять на том, чтобыthrow
аргумент имел различимый тип класса. Выражение вроде(System.InvalidOperationException)null
должно быть действительным во время компиляции (его выполнение должно вызывать aNullReferenceException
), но это не означает, что нетипизированноеnull
должно быть приемлемо.Попытка выбросить
null
объект приводит к (совершенно не связанному) исключению нулевой ссылки.Спрашивать, почему вам разрешено бросать, все
null
равно что спрашивать, почему вам разрешено это делать:object o = null; o.ToString();
источник
Взято отсюда :
источник
Хотя в C # может быть невозможно выбросить null, потому что throw обнаружит это и превратит его в исключение NullReferenceException, возможно получить null ... Я получаю это прямо сейчас, что вызывает мой улов (который не был ожидая, что ex будет иметь значение null), чтобы испытать исключение нулевой ссылки, которое затем приведет к смерти моего приложения (поскольку это была последняя проблема).
Итак, хотя мы не можем выбросить null из C #, преисподняя может выбросить null, поэтому ваш внешний улов (Exception ex) лучше подготовиться к его получению. Просто к вашему сведению.
источник
Я думаю, что, возможно, вы не можете - когда вы пытаетесь выбросить null, он не может, поэтому он делает то, что должен, в случае ошибки, а именно генерирует исключение нулевой ссылки. Таким образом, вы на самом деле не выбрасываете null, вы не можете выбросить null, что приводит к выбросу.
источник
Пытаюсь ответить «… слава богу, ex не является нулем, но может ли это когда-нибудь быть?»:
Поскольку мы, вероятно, не можем генерировать исключения с нулевым значением, предложению catch также никогда не придется перехватывать нулевое исключение. Таким образом, ex никогда не может быть нулевым.
Теперь я вижу, что этот вопрос, по сути, уже задавался .
источник
throw null
. Но это не вызовет исключения с нулевым значением . Скорее, посколькуthrow null
пытается вызвать методы для нулевой ссылки, это впоследствии заставляет среду выполнения генерировать ненулевой экземплярNullReferenceException
.Помните, что исключение включает подробную информацию о том, где возникло исключение. Поскольку конструктор не знает, куда он должен быть брошен, имеет смысл только то, что метод throw вводит эти детали в объект в точке, где находится выброс. Другими словами, среда CLR пытается ввести данные в значение null, что вызывает исключение NullReferenceException.
Не уверен, что именно это происходит, но это объясняет феномен.
Предполагая, что это правда (и я не могу придумать лучшего способа получить значение ex равным null, чем throw null;), это будет означать, что ex не может быть нулевым.
источник
В более старом С #:
Рассмотрим этот синтаксис:
public void Add<T> ( T item ) => throw (hashSet.Add ( item ) ? null : new Exception ( "The item already exists" ));
Я думаю, что это намного короче:
public void Add<T> ( T item ) { if (!hashSet.Add ( item )) throw new Exception ( "The item already exists" ); }
источник