2016-12-21 26 views
2

在D語言中,我想迭代一個結構並執行特定於每個成員附加的每個註釋的邏輯。防爆。D語言:遍歷結構的成員並檢查UDA(運行時反射)

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; 
} 

我該怎麼辦呢?

回答

3

有兩種方法可以做到這一點。如果它是一個結構體,我會用__traits(allMembers, T),但爲了上課,我會與__traits(derivedMembers, T)一起去確保您不會從對象繼承或其他您不感興趣的實例中獲取垃圾(如果您希望從所有成員都不會參加)。

對於可能是結構體或類的通用情況,但您不確定,爲安全起見,我會使用derivedMembers

你應該做的,雖然是使用__traits(compiles)防範私有成員,因爲allMembersderivedMembers也將返回私處等

參見: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

+0

哇,這是聰明的。 Mixin魔法永遠不會令我驚歎。當我有更多時間時,我會嘗試這個。 – FatalCatharsis

+0

如果它的工作,請接受答案:)但是,弦串mixins是驚人的,讓我們做任何事情 – Bauss

+0

工作就像一個魅力。我必須做的唯一調整是刪除elses,以便處理一個成員的多個屬性。 – FatalCatharsis