Looking for c# Keywords? Try Ask4Keywords

C# Language Создание пользовательских исключений


пример

Вам разрешено выполнять пользовательские исключения, которые могут быть выбрасываться точно так же, как и любое другое исключение. Это имеет смысл, если вы хотите, чтобы ваши исключения отличались от других ошибок во время выполнения.

В этом примере мы создадим настраиваемое исключение для четкой обработки проблем, которые может иметь приложение при анализе сложного ввода.

Создание пользовательского класса исключений

Чтобы создать настраиваемое исключение, создайте подкласс класса Exception :

public class ParserException : Exception
{
    public ParserException() : 
      base("The parsing went wrong and we have no additional information.") { }
}

Пользовательское исключение становится очень полезным, когда вы хотите предоставить дополнительную информацию улову:

public class ParserException : Exception
{
    public ParserException(string fileName, int lineNumber) : 
      base($"Parser error in {fileName}:{lineNumber}") 
    {
      FileName = fileName;
      LineNumber = lineNumber;
    }
    public string FileName {get; private set;}
    public int LineNumber {get; private set;}    
}

Теперь, когда вы catch(ParserException x) вас будет дополнительная семантика для точной настройки обработки исключений.

Пользовательские классы могут реализовать следующие функции для поддержки дополнительных сценариев.

повторно метания

Во время процесса синтаксического анализа исходное исключение по-прежнему представляет интерес. В этом примере это FormatException потому что код пытается разобрать кусок строки, который, как ожидается, будет числом. В этом случае пользовательское исключение должно поддерживать включение « InnerException »:

//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}

сериализация

В некоторых случаях ваши исключения могут пересекать границы AppDomain. Это так, если ваш парсер работает в своем AppDomain для поддержки горячей перезагрузки новых конфигураций парсера. В Visual Studio вы можете использовать шаблон Exception для генерации кода, подобного этому.

[Serializable]
public class ParserException : Exception
{
    // Constructor without arguments allows throwing your exception without
    // providing any information, including error message. Should be included
    // if your exception is meaningful without any additional details. Should
    // set message by calling base constructor (default message is not helpful).
    public ParserException()
        : base("Parser failure.")
    {}

    // Constructor with message argument allows overriding default error message.
    // Should be included if users can provide more helpful messages than
    // generic automatically generated messages.
    public ParserException(string message) 
        : base(message)
    {}

    // Constructor for serialization support. If your exception contains custom
    // properties, read their values here.
    protected ParserException(SerializationInfo info, StreamingContext context) 
        : base(info, context)
    {}
}

Использование исключения ParserException

try
{
    Process.StartRun(fileName)
}
catch (ParserException ex)
{
    Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x) 
{
    ...
}

Вы также можете использовать пользовательские исключения для исключений catching и wrapping. Таким образом, многие различные ошибки могут быть преобразованы в один тип ошибки, который более полезен для приложения:

try
{
    int foo = int.Parse(token);
}
catch (FormatException ex)
{
    //Assuming you added this constructor
    throw new ParserException(
      $"Failed to read {token} as number.", 
      FileName, 
      LineNumber, 
      ex);
}

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

Проблемы безопасности

Если разоблачение причины исключения может поставить под угрозу безопасность, позволяя пользователям видеть внутреннюю работу вашего приложения, может быть плохая идея обернуть внутреннее исключение. Это может применяться, если вы создаете библиотеку классов, которая будет использоваться другими.

Вот как вы могли бы создать настраиваемое исключение без обертывания внутреннего исключения:

try
{
  // ...
}
catch (SomeStandardException ex)
{
  // ...
  throw new MyCustomException(someMessage);
}

Заключение

При создании настраиваемого исключения (с оберткой или с помощью развернутого нового исключения) вы должны создать исключение, имеющее смысл для вызывающего. Например, пользователь библиотеки классов может не знать о том, как эта библиотека выполняет свою внутреннюю работу. Исключения, вызванные зависимостями библиотеки классов, не имеют смысла. Скорее, пользователь хочет исключение, которое имеет отношение к тому, как библиотека классов использует эти зависимости ошибочным способом.

try
{
  // ...
}
catch (IOException ex)
{
  // ...
  throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details. 
If you are not able to resolve the problem, please call 555-555-1234 for technical       
assistance.", ex);
}