2016-12-21 7 views
2

В языке D я хочу перебирать структуру и выполнять логику, специфичную для каждой аннотации, прикрепленной к каждому члену. Ex.Язык 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

Wow, что умна. Миксиновая магия никогда не перестает меня удивлять. Я попробую это, когда у меня будет больше времени. – FatalCatharsis

+0

Если это сработает, пожалуйста, примите ответ :) Но да, струнные миксины потрясающие, и давайте сделаем что-нибудь в целом – Bauss

+0

Работали как шарм. Единственной корректировкой, которую я должен был сделать, было удаление elses, так что все атрибуты на члене были бы обработаны. – FatalCatharsis

 Смежные вопросы

  • Нет связанных вопросов^_^