Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Исключения используются для указания того, что при запуске программы произошла ошибка. Объекты исключений, описывающие ошибку, создаются, а затем выбрасываются с помощью инструкции throw
или выражения. Затем среда выполнения выполняет поиск наиболее совместимого обработчика исключений.
Программисты должны создавать исключения, если одно или несколько следующих условий являются истинными:
Метод не может осуществить свою определенную функциональность. Например, если параметр метода имеет недопустимое значение:
static void CopyObject(SampleClass original) { _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original)); }
Неуместный вызов объекта выполняется на основе состояния объекта. Одним из примеров может быть попытка записи в файл, доступный только для чтения. В случаях, когда состояние объекта не разрешает операцию, бросьте экземпляр InvalidOperationException или объект, основанный на производной от этого класса. Следующий код является примером метода, который создает объект InvalidOperationException:
public class ProgramLog { FileStream logFile = null!; public void OpenLog(FileInfo fileName, FileMode mode) { } public void WriteLog() { if (!logFile.CanWrite) { throw new InvalidOperationException("Logfile cannot be read-only"); } // Else write data to the log and return. } }
Если аргумент метода вызывает исключение. В этом случае исходное исключение должно быть поймано, и необходимо создать экземпляр ArgumentException. Исходное исключение должно быть передано конструктору ArgumentException в качестве параметра InnerException:
static int GetValueFromArray(int[] array, int index) { try { return array[index]; } catch (IndexOutOfRangeException e) { throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
Заметка
В предыдущем примере показано, как использовать свойство
InnerException
. Это намеренно упрощено. На практике необходимо проверить, находится ли индекс в диапазоне перед его использованием. Можно применять эту технику для оборачивания исключения в случаях, когда член параметра выбрасывает исключение, которое невозможно было предвидеть перед вызовом.
Исключения содержат свойство с именем StackTrace. Эта строка содержит имя методов в текущем стеке вызовов вместе с именем файла и номером строки, в котором исключение было создано для каждого метода. Объект StackTrace создается автоматически средой CLR из точки инструкции throw
, поэтому исключения должны быть вызваны с точки начала трассировки стека.
Все исключения содержат свойство с именем Message. Эта строка должна быть задана, чтобы объяснить причину исключения. Сведения, конфиденциальные для безопасности, не должны быть помещены в текст сообщения. Помимо Message, ArgumentException содержит свойство с именем ParamName, которое должно быть задано в качестве имени аргумента, вызвавшего исключение. В сеттере свойства ParamName должно быть установлено значение value
.
Общедоступные и защищенные методы создают исключения всякий раз, когда они не могут завершить свои предполагаемые функции. Создаваемый класс исключений — это наиболее конкретное исключение, которое соответствует условиям ошибки. Эти исключения должны быть задокументированы как часть функциональных возможностей класса, а производные классы или обновления исходного класса должны сохранять то же поведение для обратной совместимости.
Вещи, которых следует избегать при генерации исключений
В следующем списке указаны практики, которых следует избегать при выбрасывании исключений.
- Не используйте исключения для изменения потока программы в рамках обычного выполнения. Используйте исключения для создания отчетов и обработки условий ошибок.
- Исключения не следует возвращать как возвращаемое значение или параметр, вместо того чтобы выбрасываться.
- Не выбрасывайте System.Exception, System.SystemException, System.NullReferenceExceptionили System.IndexOutOfRangeException из собственного исходного кода намеренно.
- Не создавайте исключения, которые можно создавать в режиме отладки, но не в режиме выпуска. Чтобы выявлять ошибки во время выполнения на этапе разработки, используйте Debug Assert.
Исключения в методах возврата задач
Методы, объявленные модификатором async
, имеют некоторые особые аспекты, когда речь идет об исключениях. Исключения, создаваемые в методе async
, хранятся в возвращаемой задаче и не возникают до тех пор, пока, например, задача ожидается. Дополнительные сведения о хранимых исключениях см. в разделе Асинхронные исключения.
Рекомендуется проверить аргументы и вызвать все соответствующие исключения, например ArgumentException и ArgumentNullException, перед вводом асинхронных частей методов. То есть эти исключения проверки должны возникать синхронно перед началом работы. В следующем фрагменте кода показан пример, в котором при возникновении исключений ArgumentException исключения будут синхронно возникать, в то время как InvalidOperationException будут храниться в возвращаемой задаче.
// Non-async, task-returning method.
// Within this method (but outside of the local function),
// any thrown exceptions emerge synchronously.
public static Task<Toast> ToastBreadAsync(int slices, int toastTime)
{
if (slices is < 1 or > 4)
{
throw new ArgumentException(
"You must specify between 1 and 4 slices of bread.",
nameof(slices));
}
if (toastTime < 1)
{
throw new ArgumentException(
"Toast time is too short.", nameof(toastTime));
}
return ToastBreadAsyncCore(slices, toastTime);
// Local async function.
// Within this function, any thrown exceptions are stored in the task.
static async Task<Toast> ToastBreadAsyncCore(int slices, int time)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
// Start toasting.
await Task.Delay(time);
if (time > 2_000)
{
throw new InvalidOperationException("The toaster is on fire!");
}
Console.WriteLine("Toast is ready!");
return new Toast();
}
}
Определение классов исключений
Программы могут создавать предопределенный класс исключений в пространстве имен System (за исключением тех, где ранее было указано), или создавать собственные классы исключений, производные от Exception. Производные классы должны определять по крайней мере три конструктора: один конструктор без параметров, один из них задает свойство сообщения и задает свойства Message и InnerException. Например:
[Serializable]
public class InvalidDepartmentException : Exception
{
public InvalidDepartmentException() : base() { }
public InvalidDepartmentException(string message) : base(message) { }
public InvalidDepartmentException(string message, Exception inner) : base(message, inner) { }
}
Добавьте новые свойства в класс исключений, когда предоставленные данные полезны для разрешения исключения. Если новые свойства добавляются в производный класс исключений, ToString()
следует переопределить, чтобы вернуть добавленную информацию.
Спецификация языка C#
Дополнительные сведения см. в исключениях и операторе throw в Спецификации языка C#. Спецификация языка является окончательным источником для синтаксиса И использования C#.