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

  • 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.

主站蜘蛛池模板: 永泰县| 聂荣县| 崇州市| 开阳县| 乐昌市| 义乌市| 多伦县| 嘉峪关市| 九龙县| 农安县| 阳高县| 蕉岭县| 祁东县| 北票市| 镇雄县| 兴隆县| 曲水县| 建阳市| 普宁市| 武定县| 青浦区| 大悟县| 合山市| 景东| 永定县| 金溪县| 思南县| 新龙县| 彰化县| 青龙| 镇宁| 拜泉县| 弋阳县| 射阳县| 哈尔滨市| 罗源县| 洮南市| 丰县| 台东市| 雅安市| 新郑市|