0Pricing
C# Academy · Урок

Пользовательские исключения и проектирование ошибок

Создавайте небольшие пользовательские исключения, выбирайте подходящие встроенные типы (ArgumentException, InvalidOperationException) и добавляйте контекст с помощью InnerException.

«Пользовательские исключения и проектирование ошибок» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 3 уроков всего.

Назначение и цели

Цель: сделать ошибки понятными и доступными для перехвата.

  • Использовать конкретный тип для конкретной причины сбоя
  • Добавлять хорошее сообщение и InnerException для контекста
  • Отдавать предпочтение встроенным типам, когда они подходят

Пользовательский тип исключения

Наследуйте тип от Exception, заканчивайте его имя суффиксом Exception и добавьте стандартные конструкторы. Храните небольшие полезные данные.

using System;

// Custom, specific to our domain
public sealed class ConfigNotFoundException : Exception
{
  public string Key { get; private set; }

  public ConfigNotFoundException(string key)
    : base("Config key not found: " + key)
  {
    Key = key;
  }

  public ConfigNotFoundException(string key, Exception inner)
    : base("Config key not found: " + key, inner)
  {
    Key = key;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      throw new ConfigNotFoundException("ApiUrl");
    }
    catch (ConfigNotFoundException ex)
    {
      Console.WriteLine(ex.Message);
    }
  }
}

InnerException для контекста

Оборачивайте исключения нижнего уровня в доменное исключение и устанавливайте InnerException, чтобы сохранить корневую причину.

using System;
using System.IO;

public sealed class ConfigNotFoundException : Exception
{
  public string Key { get; private set; }
  public ConfigNotFoundException(string key, Exception inner)
    : base("Config key not found: " + key, inner) { Key = key; }
}

public static class Config
{
  public static string Load(string path, string key)
  {
    try
    {
      string[] lines = File.ReadAllLines(path); // may throw
      for (int i = 0; i < lines.Length; i++)
      {
        int idx = lines[i].IndexOf("=");
        if (idx > 0 && lines[i].Substring(0, idx) == key)
          return lines[i].Substring(idx + 1);
      }
      throw new ConfigNotFoundException(key, null);
    }
    catch (IOException io)
    {
      // Wrap low-level error with domain meaning
      throw new ConfigNotFoundException(key, io);
    }
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      Console.WriteLine(Config.Load("missing.cfg", "ApiUrl"));
    }
    catch (ConfigNotFoundException ex)
    {
      Console.WriteLine("Top: " + ex.Message);
      if (ex.InnerException != null)
        Console.WriteLine("Inner: " + ex.InnerException.GetType().Name);
    }
  }
}

Сначала выбирайте встроенные типы

Используйте встроенные типы для распространённых проблем: ArgumentNullException, ArgumentOutOfRangeException, FormatException, InvalidOperationException и т. д.

using System;

public static class MathUtil
{
  public static int Divide(int a, int b)
  {
    if (b == 0) throw new DivideByZeroException();
    return a / b;
  }

  public static int ParsePositive(string text)
  {
    if (text == null) throw new ArgumentNullException("text");
    int value = int.Parse(text); // may throw FormatException
    if (value <= 0) throw new ArgumentOutOfRangeException("text", "must be > 0");
    return value;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try { Console.WriteLine(MathUtil.ParsePositive("-1")); }
    catch (ArgumentOutOfRangeException ex) { Console.WriteLine("Range: " + ex.ParamName); }
  }
}

Исключения и защитные проверки

Используйте исключения для исключительных ситуаций. Для ожидаемых сбоев отдавайте предпочтение защитным проверкам TryX или кодам возврата.

using System;

public static class Parser
{
  // BAD: using exceptions for expected cases
  public static int ParseOrThrow(string s)
  {
    return int.Parse(s); // will throw often for user input
  }

  // GOOD: guard-check pattern for expected failure
  public static bool TryParsePositive(string s, out int value)
  {
    value = 0;
    int tmp;
    if (!int.TryParse(s, out tmp)) return false;
    if (tmp <= 0) return false;
    value = tmp;
    return true;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    int v;
    if (Parser.TryParsePositive("12", out v))
      Console.WriteLine("OK " + v);
    else
      Console.WriteLine("Invalid");
  }
}

Контрольный список проектирования ошибок

Контрольный список:

  • По возможности выбирайте встроенный тип.
  • В противном случае создавайте небольшое CustomException со стандартными конструкторами.
  • Добавляйте InnerException, чтобы сохранить корневую причину.
  • Используйте исключения для непредвиденных случаев, а TryX — для ожидаемых сбоев.

Проектирование пользовательских исключений

Быстрая проверка: как рекомендуется проектировать пользовательский тип исключения в C#?

Повторение

Повторение: отдавайте предпочтение встроенным исключениям; в противном случае определите небольшой пользовательский тип со стандартными конструкторами и используйте InnerException, чтобы добавить контекст, не теряя причину ошибки.

Часто задаваемые вопросы

Урок «Пользовательские исключения и проектирование ошибок» бесплатный?

Да — полный текст урока «Пользовательские исключения и проектирование ошибок» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 3 уроков всего.

Чему я научусь в уроке «Пользовательские исключения и проектирование ошибок»?

Создавайте небольшие пользовательские исключения, выбирайте подходящие встроенные типы (ArgumentException, InvalidOperationException) и добавляйте контекст с помощью InnerException. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 3.

Сколько времени занимает урок «Пользовательские исключения и проектирование ошибок»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. try/catch/finally, создание исключения и повторный выброс
  2. Пользовательские исключения и проектирование ошибок
  3. IDisposable и оператор using
← Назад к C# Academy