d更好异常

原文

module arsd.exception;
interface ThrowableBase {
    void fly(string file = __FILE__, size_t line = __LINE__); //应该内置在编译器的throw语句中

    // 需要时覆盖
    void printMembers(scope void delegate(in char[]) sink) const; // 用mixin PrintMembers;插件
    void getHumanReadableMessage(scope void delegate(in char[]) sink) const;//可读信息
    void printName(scope void delegate(in char[]) sink) const; // 不喜欢rtti时


    // 准备好时就调用它
    void toString(scope void delegate(in char[]) sink) const;
}

mixin template ThrowableBaseImplementation() {
    // 在抛出点而不是在 ctor 中,设置文件和行
    // 从而分开分配与错误信息
    // 将设置file+line,从而简化重用.
    void fly(string file = __FILE__, size_t line = __LINE__) {
        this.file = file;
        this.line = line;
        throw this;
    }

    /* virtual */ void getHumanReadableMessage(scope void delegate(in char[]) sink) const {
        sink(msg); // 兼容
    }

    // 打印真正有用的信息
    // 用下面插件
    /* virtual */ void printMembers(scope void delegate(in char[]) sink) const {
        // 插件
    }

    /* virtual */ void printName(scope void delegate(in char[]) sink) const {
        sink(typeid(this).name); 
    }

    override void toString(scope void delegate(in char[]) sink) const {
        char[32] tmpBuff = void;
        printName(sink);
        sink("@"); sink(file);
        sink("("); sink(line.sizeToTempString(tmpBuff[])); sink(")");
        sink(": "); getHumanReadableMessage(sink);
        sink("\n");
        printMembers(sink);
        if (info) {
            try {
                sink("----------------");
                foreach (t; info) {
                    sink("\n"); sink(t);
                }
            }
            catch (Throwable) {
                // 忽略
            }
        }
    }

}

class ExceptionBase : Exception, ThrowableBase {
    // 大大简化
    this() {
        super("");
    }

    mixin ThrowableBaseImplementation;
}

class ErrorBase : Error, ThrowableBase {
    this() { super(""); }
    mixin ThrowableBaseImplementation;
}

// 派生类中来自动打印`所有成员`以方便调试的插件
mixin template PrintMembers() {
    override void printMembers(scope void delegate(in char[]) sink) const {
        foreach(memberName; __traits(derivedMembers, typeof(this))) {
            static if(is(typeof(__traits(getMember, this, memberName))) && !is(typeof(__traits(getMember, typeof(this), memberName)) == function)) {
                sink("\t");
                sink(memberName);
                sink(" = ");
                static if(is(typeof(__traits(getMember, this, memberName)) : const(char)[]))
                    sink(__traits(getMember, this, memberName));
                else static if(is(typeof(__traits(getMember, this, memberName)) : long)) {
                    char[32] tmpBuff = void;
                    sink(sizeToTempString(__traits(getMember, this, memberName), tmpBuff));
                } // else pragma(msg, typeof(__traits(getMember, this, memberName)));
                sink("\n");
            }
        }

        super.printMembers(sink);
    }
}

mixin template StaticHumanReadableMessage(string s) {
    override void getHumanReadableMessage(scope void delegate(in char[]) sink) const {
        sink(s);
    }
}





interface DynamicException {
    /*
    TypeInfo getArgumentType(size_t idx);
    void*    getArgumentData(size_t idx);
    string   getArgumentAsString(size_t idx);
    */
}//动态异常

template enforceBase(ExceptionBaseClass, string failureCondition = "ret is null") {
    auto enforceBase(alias func, string file = __FILE__, size_t line = __LINE__, T...)(T args) {
        auto ret = func(args);
        if(mixin(failureCondition)) {
            class C : ExceptionBaseClass, DynamicException {
                T args;
                this(T args) {
                    this.args = args;
                }

                override void printMembers(scope void delegate(in char[]) sink) const {
                    import std.traits;
                    import std.conv;
                    foreach(idx, arg; args) {
                        sink("\t");
                        sink(ParameterIdentifierTuple!func[idx]);
                        sink(" = ");
                        sink(to!string(arg));
                        sink("\n");
                    }
                    sink("\treturn value = ");
                    sink(to!string(ret));
                    sink("\n");
                }

                override void printName(scope void delegate(in char[]) sink) const {
                    sink(__traits(identifier, ExceptionBaseClass));
                }

                override void getHumanReadableMessage(scope void delegate(in char[]) sink) const {
                    sink(__traits(identifier, func));
                    sink(" call failed");
                }
            }

            auto exception = new C(args);
            exception.file = file;
            exception.line = line;
            throw exception;
        }

        return ret;
    }
}

/// 抛给定一组要打印的局部变量,异常
void raise(ExceptionBaseClass, T...)(string file = __FILE__, size_t line = __LINE__) {
    class C : ExceptionBaseClass, DynamicException {
        override void printMembers(scope void delegate(in char[]) sink) const {
            import std.conv;
            foreach(idx, arg; T) {
                sink("\t");
                sink(__traits(identifier, T[idx]));
                sink(" = ");
                sink(to!string(arg));
                sink("\n");
            }
        }

        override void printName(scope void delegate(in char[]) sink) const {
            sink(__traits(identifier, ExceptionBaseClass));
        }
    }

    auto exception = new C();
    exception.file = file;
    exception.line = line;
    throw exception;
}

const(char)[] sizeToTempString(long size, char[] buffer) {
    size_t pos = buffer.length - 1;
    bool negative = size < 0;
    if(size < 0)
        size = -size;
    while(size) {
        buffer[pos] = size % 10 + '0';
        size /= 10;
        pos--;
    }
    if(negative) {
        buffer[pos] = '-';
        pos--;
    }
    return buffer[pos + 1 .. $];
}

//示例:

class MyRangeError : ErrorBase {
    // 不必要但有静态错误消息有点好
    mixin StaticHumanReadableMessage!"越界";
}

// 创建新类
class TypedRangeError(T) : MyRangeError {
    // 详细错误信息,在数据成员中
    this(T index) {
        this.index = index;
    }

    mixin StaticHumanReadableMessage!(T.stringof ~ " index out of bounds");

    // 提供了更多信息并且无需分配
    T index;

    mixin PrintMembers;//插件.
}

version(exception_2_example) {

    // 可传递预先构造异常给函数,并得到良好的文件/行和堆栈跟踪信息
    void stackExample(ThrowableBase exception) {
        // 抛
        exception.fly(); // 抛语句
    }

    void main() {
        int a = 230;
        string file = "lol";
        static class BadValues : ExceptionBase {}
        //raise!(BadValues, a, file);

        alias enforce = enforceBase!ExceptionBase;

        import core.stdc.stdio;
        auto fp = enforce!fopen("nofile.txt".ptr, "rb".ptr);


        // 构造,按数据,而非串传递
        auto exception = new TypedRangeError!int(4); // 异常构造与文件/行设置分离
        stackExample(exception); 
// 可以在A分配/构造,然后在B地设置和抛出
    }
}
posted @   zjh6  阅读(13)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示