官术网_书友最值得收藏!

  • D Cookbook
  • Adam D. Ruppe
  • 572字
  • 2021-07-16 11:50:44

Using a custom exception type

D uses exceptions to handle errors, just like many other programming languages. In D, exceptions are always implemented as classes that derive from the class Throwable, and they are differentiated by their type. So, it is best to generate a new exception subclass for different types of errors your code can generate. This way, users of your code will get the most information and control out of your exceptions.

How to do it…

Let's use a custom exception type by using the following steps:

  1. Declare a class that inherits from Exception.
  2. Make a constructor that takes, minimally, two parameters: string file and size_t line, with default values of __FILE__ and __LINE__, respectively.
  3. Have the constructor forward the arguments to the constructor of Exception.
  4. Use your exception.

The following is the code:

class MyException : Exception {
    this(string message, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
          super(message, file, line, next);
    }
}

void main() {
    import std.stdio;
    try
      throw new MyException("message here");
    catch(MyException e)
      writeln("caught ", e);
}

How it works…

D uses exceptions to handle errors. All throwable objects inherit from either Exception, for recoverable events, or Error for unrecoverable errors, which generally ought not be caught. The common base class is Throwable.

Typically, a custom exception inherits from Exception, then declares, minimally, a constructor that forwards the functionality to super(). You may also store additional information specific to your use case.

The constructor of Exception (here, called with super()) takes four arguments: a string message, a filename, a line number, and optionally, a reference to another exception. The message, filename, and line number are used to construct a message for the user, which is printed to the console if the exception is not caught.

You don't have to specify the file and line number at the throw site; any default argument of __FILE__ or __LINE__ is automatically expanded at the function's call site. This is useful to make the error message more useful by showing exactly where the exception came from.

The fourth parameter, Throwable next, is used if an exception handler throws an exception. It references the exception that was being handled when this one was generated.

Tip

To get full stack trace symbols in the printed exception, you may need to compile with the debug information enabled by using dmd –g.

There's more…

You should check error codes when using the C functions and turn them into exceptions. If it sets errno for error details, the std.exception module has a subclass called ErrnoException that is perfect for the following code:

import core.sys.posix.unistd; // for the low-level Posix functions
import core.sys.posix.fnctl // for more low-level Posix functions
import std.exception; // for ErrnoException
auto fd = open("myfile.txt", O_RDONLY);
// open() returns -1 if it was unable to open the file,
// and sets errno with error details. Check for that failure.
if(fd == -1)
    throw new ErrnoException("Couldn't open myfile.txt");
// close the file automatically at the end of the scope
scope(exit) close(fd);
/* read the file here */

See also

Scope guards, discussed in Chapter 5, Resource Management, are convenient for use with exceptions. They let you put clean-up or recovery code near the creation point in an exception-safe way. In the preceding example, you used a scope guard to ensure the file is properly closed when the function returns, even if an exception is thrown.

主站蜘蛛池模板: 正镶白旗| 台湾省| 平遥县| 五原县| 股票| 承德市| 原阳县| 新干县| 瓦房店市| 普兰店市| 临武县| 高青县| 榆中县| 南汇区| 泸定县| 黎城县| 伊川县| 广安市| 临夏市| 瑞丽市| 大理市| 南昌县| 博兴县| 大兴区| 仙居县| 兰考县| 扶绥县| 衢州市| 汶川县| 长丰县| 台北市| 南阳市| 德令哈市| 方山县| 深水埗区| 兴安县| 宁远县| 宁强县| 和平县| 平乐县| 信丰县|