2013-01-09 30 views
2

我想了解更多關於D的編譯時間評估,並瞭解它的模板,mixins,屬性等如何工作。我想嘗試做的一件事是找出將類的成員標記爲可序列化或可從數據庫加載的優雅方法。在下面的示例中,我創建了一個元組,列出在讀取或(稍後)序列化實例時要使用的成員。用戶定義屬性和編譯時間評估設置類成員變量

我的第一個問題是,這是元組的正確用法嗎?其次,如果是這樣,是否有一種方法可以在編譯時使用我已分配給相關成員變量的用戶定義屬性自動生成此元組?我已經瀏覽了各種文檔頁面,如http://dlang.org/attribute.htmlhttp://dlang.org/phobos/std_traits.html,但我似乎無法弄清楚如何正確使用它們(即循環遍歷類的成員並確定哪些變量具有所需的屬性)。我也不太確定,如果我完全錯誤地認爲應該如何使用屬性。任何建議最好的方式去這個將不勝感激。

enum ENCODABLE = 1; 
alias string[string] Row; 
template Tuple (T...) { alias T Tuple; } 

class A { 
    @(ENCODABLE) string name; 
    @(ENCODABLE) int x; 
    int* p; 

    alias Tuple!("name","x") encodables; 

    this(Row row) { 
     foreach (var; encodables) { 
      __traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]); 
     } 
    } 
} 

void main() { 
    Row row = ["name":"Asdf", "x":"120"]; // Simulated database row 
    auto a = new A(row); 
    writefln("%s,%d,%d", a.name, a.x, a.p); // Asdf,120,null 
} 

回答

0

我已經成功地得到它使用下面的代碼,以及基於Cyber​​Shadow答案中提供的代碼的isValueInTuple模板的一些幫助。它仍然感覺有點笨重,但似乎完成了這項工作。評論/批評歡迎,如果我對模板的性質做了一些可怕的事情!

enum { 
    ENCODABLE = "ENCODABLE", 
}; 
alias string[string] Row; 
template Tuple(T...) { alias T Tuple; } 
template isValueInTuple(string s, T...) { 
    static if (T.length == 0) { 
     enum bool isValueInTuple = false; 
    } else static if (T.length == 1) { 
     static if (is(typeof(T[0]) == typeof(s))) { 
      enum bool isValueInTuple = T[0] == s; 
     } else { 
      enum bool isValueInTuple = false; 
     } 
    } else { 
     enum bool isValueInTuple = isValueInTuple!(s, T[0]) || isValueInTuple!(s, T[1..$]); 
    } 
} 
template GenEncodables(U) { 
    string GenEncodables() { 
     string ret = "alias Tuple!("; 
     int fn = 0; 
     foreach (index, field; __traits(allMembers, U)) { 
      static if (field != "Monitor") { // better way to avoid compilation errors here? 
       static if (isAssignable!(typeof(mixin(U.stringof~"."~field)))) { 
        static if (isValueInTuple!(ENCODABLE, __traits(getAttributes, mixin(U.stringof~"."~field)))) { 
         if (fn++) 
          ret ~= ","; 
         ret ~= `"`~field~`"`; 
        } 
       } 
      } 
     } 
     ret ~= ") encodables;"; 
     return ret; 
    } 
} 
mixin template Encodables() { 
    mixin(GenEncodables!(typeof(this))); 
} 


class A { 
    @ENCODABLE string name; 
    @ENCODABLE int x; 
    int *p; 

    this() {} 

    mixin Encodables; // must come after this() definition, apparently! 

    this(Row row) { 
     foreach (var; encodables) { 
      pragma(msg, "Reading parameter "~var~" from row"); 
      __traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]); 
     } 
    } 
}