Почему CLS предписывает создание / перехват объектов, производных от Exception?
CLS является более строгим, чем CLR, что позволит вам бросать и ловить любые типы объектов (даже типы значений). Зачем?
Кроме того, что произойдет, если какой-то не совместимый с CLS код бросит объект, не являющийся производным от исключения, при вызове кодом, совместимым с CLS?
ОБНОВЛЕНИЕ Второй вопрос ответил @Marton. Все еще удивляюсь почему.
2 ответа
CLS определяет минимальный набор языковых функций, необходимых многим приложениям таким образом, что, если API использует только эти функции, он может использоваться любым CLS-совместимым языком. Поэтому, естественно, это более ограничительный, чем CLR. С другой стороны, CLR предназначен для обработки управляемого кода с любого CLI-совместимого языка.
Примером языка, который позволяет выбрасывать не-CLS-совместимые исключения (те, которые не являются производными от System.Exception), является C++/CLI. Этот язык был разработан, чтобы быть надмножеством простого C++, который включает в себя возможность генерировать исключения любого типа. Это может быть единственной веской причиной для исключения не-CLS.
По поводу второго вопроса. Исключение, не относящееся к CLS, при возникновении в разных случаях происходят разные вещи:
- Если CLR 1.X управляет выполнением кода, исключение распространяется как есть. В языках, которые поддерживают только исключения CLS (C#), исключение может быть перехвачено только блоком перехвата без параметров. Нет простого способа получить доступ к исключению, и трассировка стека не будет записана.
В CLR 2.0 и более поздних версиях CLR внутренне всегда помещает исключение в System.Runtime.CompilerServices.RuntimeWrappedException, которое поддерживает поле типа Object, которое ссылается на исходное исключение. Это позволяет записывать трассировку стека. Когда он распространяется вверх по стеку:
Если атрибут System.Runtime.CompilerServices.RuntimeCompatibilityAttribute был применен к сборке функции, в которой CLR ищет соответствующий блок catch, а WrapNonExceptionThrows установлен в значение true (автоматически применяется компиляторами Visual C# и Basic), то исключение продолжается быть завернутым.
В противном случае, если атрибут не был применен или если для WrapNonExceptionThrows задано значение false, исключение разворачивается каждый раз, когда блок перехвата проверяется на соответствие.
редактировать
В C# в первом вышеупомянутом пункте и во втором случае второго маркера единственный способ перехватить исключение, не относящееся к CLS, состоит в использовании блока перехвата без параметров.
Часть почему я не могу ответить, но вторая часть я могу:
что произойдет, если какой-нибудь не совместимый с CLS код бросит объект, не являющийся производным от исключения, во время вызова из кода, совместимого с CLS?
Если вы бросите объект, не являющийся производным от исключения, он все равно будет перехвачен CLS-совместимым кодом, поскольку он будет заключен в RuntimeWrappedException
,
( Исходную статью стоит прочитать для более подробной информации.)