Почему C# позволяет вам "выбрасывать null"?
при написании какого-то особенно сложного кода обработки исключений кто-то спросил, не нужно ли вам убедиться, что ваш объект исключения не равен null? И я сказал, Конечно нет, но потом решил попробовать. По-видимому, вы можете бросить null, но он все равно превратился в исключение где-то.
почему это допускается?
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 ответов:
потому что спецификация языка ожидает выражение типа
System.Exception
там (поэтомуnull
является допустимым в этом контексте) и не ограничивает это выражение, чтобы быть не-null. В общем, он никак не может определить, является ли значение этого выраженияnull
или нет. Это должно было бы решить проблему остановки. Во время выполнения придется иметь дело сnull
дело в любом случае. Смотрите:Exception ex = null; if (conditionThatDependsOnSomeInput) ex = new Exception(); throw ex;
они могли бы, конечно, сделать конкретный случай забрасывания
null
литерал недействителен, но это не очень поможет, так зачем тратить пространство спецификации и уменьшать согласованность для небольшой пользы?отказ от ответственности (прежде чем я получу пощечину от Эрика Липперта): это моей размышления о причинах этого проектного решения. Конечно, я не был на совещании по дизайну ;)
ответ на ваш второй вопрос, Может ли переменная выражения, пойманная в предложении catch, когда-либо быть null: в то время как спецификация C# молчит о том, могут ли другие языки вызвать a
null
исключение для распространения, оно определяет способ распространения исключений:предложения catch, если таковые имеются, проверяются в порядке появления, чтобы найти подходящий обработчик для исключения. Первое предложение catch который определяет тип исключения или базовый тип типа исключения считается совпадением. Общее предложение catch считается совпадением для любого типа исключений. [...]
на
null
, смелое утверждение ложно. Таким образом, хотя чисто на основе того, что говорит спецификация C#, мы не можем сказать, что базовая среда выполнения никогда не будет выбрасывать null, мы можем быть уверены, что даже если это так, она будет обрабатываться только genericcatch {}
предложения.для реализаций C# на CLI мы можем обратиться к спецификации ECMA 335. Этот документ определяет все исключения, которые CLI бросает внутренне (ни один из которых не является
null
) и упоминает, что пользовательские объекты исключений создаютсяthrow
инструкция. Описание этой инструкции практически идентично C#throw
оператор (за исключением того, что он не ограничивает тип объектаSystem.Exception
):описание:
The
throw
инструкция вызывает объект исключения (типO
) на стеке и опустошает стек. Дополнительные сведения о механизме исключения см. В разделе I.
[Примечание: В то время как CLI разрешает любой объект быть брошенным, CLS описывает определенный класс исключения, который должен использоваться для языковой совместимости. конец Примечание]исключения:
System.NullReferenceException
бросается, еслиobj
иnull
.правильность:
правильный CIL гарантирует, что объект всегда либо
null
или ссылка на объект (т. е. типаO
).я считаю, что этого достаточно, чтобы заключить пойманные исключения никогда
null
.
видимо, вы можете бросить null, но он все равно превратился в исключение где-то.
попытка бросить
null
объект приводит к (совершенно не связанное) значение null ссылка исключения.спрашивая, почему вы можете бросить
null
это все равно, что спросить, почему вам разрешено это делать:object o = null; o.ToString();
хотя может быть невозможно бросить null в C#, потому что бросок обнаружит это и превратит его в исключение NullReferenceException, можно получить null... Я получаю это прямо сейчас, что приводит к тому, что мой улов (который не ожидал, что " ex " будет null) испытывает исключение null reference, которое затем приводит к тому, что мое приложение умирает (так как это был последний улов).
Итак, пока мы не можем выбросить null из C#, преисподняя может выбросить null, поэтому ваш внешний catch (исключение ex) лучше быть готовым к его получению. Просто к вашему сведению.
принято от здесь:
Если вы используете это выражение в C# код он будет бросать NullReferenceException. То есть потому что throw-оператор нуждается в объект типа Exception как его единственный параметр. Но этот самый объект есть null в моем примере.
Я думаю, может быть, вы не можете -- когда вы пытаетесь бросить null, он не может, поэтому он делает то, что должен в случае ошибки, который бросает исключение null reference. Таким образом, вы на самом деле не бросаете null, вы не можете бросить null, что приводит к броску.
пытаясь ответить "..к счастью, " ex " не является нулевым, но может ли это когда-нибудь быть?":
поскольку мы, возможно, не можем выбрасывать исключения, которые являются null, предложение catch также никогда не будет ловить исключение, которое является null. Таким образом, ex никогда не может быть null.
теперь я вижу, что этот вопрос фактически уже попросил.
помните, что исключение содержит сведения о том, где возникает исключение. Поскольку конструктор понятия не имеет, где он должен быть брошен, то имеет смысл только то, что метод throw вводит эти детали в объект в точке броска. Другими словами, среда CLR пытается ввести данные в null, что вызывает исключение NullReferenceException.
Не уверен, что это именно то, что происходит, но это объясняет феномен.
предполагаю, что это это правда (и я не могу придумать лучшего способа заставить ex быть null, чем throw null;), это означало бы, что ex не может быть null.