Хотел бы узнать ваше мнение, как правильно обрабатывать исключения в библиотеке классов, и о каких исключениях сообщать в XML-комментариях.
Давайте рассмотрим надуманный пример:
/// <summary>
/// Создаёт экземпляр класса <see cref="MyObject"/> на основе информации из файла.
/// </summary>
/// <param name="pathToFile">Путь к файлу, который содержит информацию об объекте.</param>
/// <returns>Экземпляр класса <see cref="MyObject"/>, созданный на основе информации из файла.</returns>
/// <exception cref="System.ArgumentException">Значение параметра <paramref name="pathToFile"/> равно <see langword="null"/> или имеет нулевую длину.</exception>
/// <exception cref="System.FormatException">Неправильный формат данных файла.</exception>
public MyObject CreateMyObjectFromFile<TObject>(string pathToFile)
{
if (string.IsNullOrEmpty(pathToFile))
{
throw new ArgumentException(..., "pathToFile");
}
string fileContent;
using (FileStream fStream = new FileStream(pathToFile, FileMode.Open))
using (StreamReader sReader = new StreamReader(fStream))
{
fileContent = sReader.ReadToEnd();
}
// Проверяем правильность данных.
if (...)
{
throw new FormatException(...);
}
// Вычисляем MD5 хэш-значение для одного из параметров объекта.
using (HashAlgorithm hashProvider = new MD5CryptoServiceProvider())
{
StringBuilder hashBuilder = new StringBuilder();
...
}
// Создаём и возвращаем экземпляр класса.
MyObject myObject = ...;
return myObject;
}
И так, данный метод может с генерировать два типа исключения. Если брать во внимание сторонние классы, то они могут с генерировать несколько типов исключений. Так вот, как поступить?
— Оставить как есть — это приемлемый вариант.
— Оставить как есть, но в XML-комментарии добавить все возможные исключения сторонних классов, просто скопировав их описание из документации.
— Сделать обёртку try-catch-finally над каждым потенциально-опасным вызовом. В catch сделать повторную генерацию исключения с пояснением ошибки и задать начальное исключение. В XML-комментариях указать все эти возможные исключения:
/// <summary>
/// Создаёт экземпляр класса <see cref="MyObject"/> на основе информации из файла.
/// </summary>
/// <param name="pathToFile">Путь к файлу, который содержит информацию об объекте.</param>
/// <returns>Экземпляр класса <see cref="MyObject"/>, созданный на основе информации из файла.</returns>
/// <exception cref="System.ArgumentException">Значение параметра <paramref name="pathToFile"/> равно <see langword="null"/> или имеет нулевую длину.</exception>
/// <exception cref="System.FormatException">Неправильный формат данных файла.</exception>
/// <exception cref="System.Security.SecurityException">У вызывающего объекта отсутствует необходимое разрешение доступа к файлу.</exception>
/// <exception cref="System.IO.IOException">Произошла ошибка ввода-вывода, при попытки считать данные файла.</exception>
/// <exception cref="System.InvalidOperationException">Ошибка при вычисления MD5 хэш-значение, так как политика FIPS-совместимого алгоритма не задействована.</exception>
public MyObject CreateMyObjectFromFile<TObject>(string pathToFile)
{
if (string.IsNullOrEmpty(pathToFile))
{
throw new ArgumentException(..., "pathToFile");
}
string fileContent;
FileStream fStream;
StreamReader sReader;
try
{
fStream = new FileStream(pathToFile, FileMode.Open);
sReader = new StreamReader(fStream);
fileContent = sReader.ReadToEnd();
}
catch (SecurityException ex)
{
throw new SecurityException("Не удалось получить доступ к файлу, который хранить информацию об объекте.", ex);
}
catch (IOException ex)
{
throw new IOException("Не удалось считать данные из файла, который хранить информацию об объекте.", ex);
}
finally
{
if (sReader != null)
{
sReader.Dispose();
}
if (fStream != null)
{
fStream.Dispose();
}
}
// Проверяем правильность данных.
if (...)
{
throw new FormatException(...);
}
HashAlgorithm hashProvider;
try
{
// Вычисляем MD5 хэш-значение для одного из параметров объекта.
hashProvider = new MD5CryptoServiceProvider();
StringBuilder hashBuilder = new StringBuilder();
...
}
catch (InvalidOperationException ex)
{
throw new InvalidOperationException("Не удалось вычислить MD5 хэш-значение для одного из параметров объекта.", ex);
}
finally
{
if (hashProvider != null)
{
hashProvider.Dispose();
}
}
// Создаём и возвращаем экземпляр класса.
MyObject myObject = ...;
return myObject;
}