D 语言:迭代结构成员并检查 UDA(运行时反射)

D language: Iterate over members of a struct and check a UDA (runtime reflection)

在 D 语言中,我想迭代一个结构并执行特定于附加到每个成员的每个注释的逻辑。例如

struct Pattern {
    string pattern;
}

string Max {
    int max;
}

string Min {
    int min;
}

struct StructToValidate {
    @Pattern("^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$")
    string phone;

    @Max(20)
    @Min(3)
    int someValue;
}

然后在一个函数中,做这样的事情:

int main() {
    StructToValidate struct;

    // begin pseudocode
    // for each member of struct mem = [phone, someValue] {
    //     if (hasUDA!(mem, Pattern)) {
    //         do stuff like validation on the runtime value of this member
    //     } else if (hasUDA!(mem, Min)) {
    //         ...
    //     } else if (hasUDA!(mem, Max)) {
    //         ...
    //     }
    // }
    //
    return 0;
}

我该怎么做?

有两种方法可以做到这一点。如果它是一个结构,我会选择 __traits(allMembers, T),但是对于 classes 我会选择 __traits(derivedMembers, T) 以确保您不会从对象继承或其他实例中获得垃圾你不感兴趣(如果你想继承 allMembers 也可以)。

对于可能是结构或 class 的一般情况,但您不确定,为了安全起见,我会选择 derivedMembers

你应该做的是使用 __traits(compiles) 来防止私有成员,因为 allMembersderivedMembers 也会 return 私有成员等

参见:https://dlang.org/spec/traits.html#compiles

我可能会这样做:

void validate(T)(T toValidate) {
    import std.traits;

    foreach (member; __traits(allMembers, T)) { // Loops through all members of "T"
        static if(__traits(compiles, __traits(getMember, T, member))) { // Guards against private members
            static if (mixin("hasUDA!(" ~ T.stringof ~ "." ~ member ~ ", Pattern)")) { // Checks if the member has the UDA "Pattern"
                // TODO: pattern
            }

            static if (mixin("hasUDA!(" ~ T.stringof ~ "." ~ member ~ ", Min)")) { // Checks if the member has the UDA "Min"
                // Gets the value from the UDA and stores it in a variable that we can use at runtime.
                auto value = getUDAs!(mixin(T.stringof ~ "." ~ member), Min)[0].min;

                // Creates an assert for validating the member's value.
                mixin("assert(toValidate." ~ member ~ " >= value);");
            }

            static if (mixin("hasUDA!(" ~ T.stringof ~ "." ~ member ~ ", Max)")) { // Checks if the member has the UDA "Max"
                // Gets the value from the UDA and stores it in a variable that we can use at runtime.
                auto value = getUDAs!(mixin(T.stringof ~ "." ~ member), Max)[0].max;

                // Creates an assert for validating the member's value.
                mixin("assert(toValidate." ~ member ~ " <= value);");
            }
        }
    }
}

你可以这样使用:

int main() {
    StructToValidate structToValidate;

    validate(structToValidate);

    return 0;
}

注意:我没有实现模式。

尽管您可以使用:

https://dlang.org/phobos/std_regex.html