Шаблоны обработки исключений для библиотеки.NET - обрабатывать, оставлять без присмотра или перерабатывать?
Я пишу библиотеку C#, чья DLL
позже будет использоваться кодом других приложений.
Когда в библиотеке есть оператор, который может выдать исключение, такое как System.IO.IOException
я должен поймать это тогда и там сам или я должен оставить это, чтобы быть пойманным программой приложения, которое использует это?
Я спрашиваю об этом, потому что я не поймал исключение в моей библиотеке. При отладке моего приложения (которое использует библиотеку) Visual Studio показывает его мне как необработанное исключение в библиотеке. Но когда I > Continue, программа продолжается, и приложение перехватывает исключение. Кажется, работает нормально.
Теперь, можно ли это сделать, то есть могут ли возникнуть проблемы при развертывании приложения? Или это должно быть абсолютно поймано в самой библиотеке? Или MSDN предлагает что-то лучшее, чем это, в качестве "лучшей практики"?
1 ответ
Написание хорошей библиотеки - это искусство и наука. Предполагая, что вы уже определились с предоставленной функциональностью и предоставили соответствующие API потребителям библиотеки, кажется, что одна проблема осталась нерешенной - обработка исключений.
В целом исключения, которые будут возникать при выполнении кода библиотеки, можно разделить на две группы: 1. Зависит от реализации и функциональности библиотеки. 2. Зависит от потребителя или системы и вне сферы интересов вашей библиотеки.
ИМХО, наилучшей практикой будет определение всех исключений, которые генерируются библиотечным кодом, и получение их либо из ApplicationException
или еще лучше из соответствующего исключения.NET с вашим префиксом, специфичным для lib, т.е. <LibShortName>FormatException
или же <LibShortName>InvalidOperationException
, Затем, если ваша библиотека должна выдавать исключение клиентскому коду, используйте исключения, полученные из библиотеки.
Если есть исключения, возникшие за пределами библиотеки, и они имеют смысл с точки зрения вашей функциональности lib, вы можете перехватить их и либо выдать новое библиотечное исключение, содержащее в качестве внутреннего исключения уже отловленное исключение, либо использовать <LibShortName>AggregateException
создать цепочку исключений, прежде чем выставлять их клиентам.
Приведенная выше схема используется во многих популярных библиотеках.NET, например, SharpSkia. Существуют и другие подходы к этой проблеме, но я считаю, что приведенный выше наиболее информативен для потребителей библиотек - они получают как можно больше информации об ошибках. Кроме того, они могут легко использовать шаблоны на основе типов при отлове и обработке исключений.
Одним из наиболее важных аспектов написания хороших библиотек является производительность. Чтобы получить лучшую для вас библиотеку, никогда не используйте исключения для потока управления в вашем коде. Исключения следует использовать исключительно для ошибок. Один из хороших примеров плохого дизайна, нарушающего вышеупомянутый образец, был ANTLR C# parser framewrok
AFAIR v2. На каком-то этапе библиотека использовала исключения для управления логикой синтаксического анализа, что было крайне неэффективно. Позже было изменено использование исключений только для условий ошибок, улучшающих производительность на несколько порядков.
Наконец, одна из лучших книг по разработке API библиотек.NET:
- Рекомендации по разработке структуры: условные обозначения , идиомы и шаблоны для многократно используемых библиотек.NET. Авторы: Кшиштоф Квалина и Брэд Адамс.
Что может быть интересным читать это обсуждения API Reviews
в закрытом и открытом выпуске из репозитория .NET Core corefx и немного старом, но все еще классическом посте. Сообщения в блоге Krzysztof Cwalina с тегами General API Design