原文在此
還有一篇
還有這裡
還有這裡都可以看看.元程式設計相關的.
我們想要:
enum sql = `
CREATE TABLE Person (
id INTEGER NOT NULL,
name TEXT,
birthday DATE
);
`;
/+
通過上面生成下面:
class Person {
int id;
string text;
Date birthday;
void save() {
/* 忽略實作 */
}
}
+/
class ObjectImpl(some_arguments) {
// 實作
}
mixin("alias " ~ some_name ~ " ObjectImpl!(whatever, args);");
struct 結查列 {
string name;
string type;
}
struct 結查表 {
string name;
結查列[] 列;
}
結查表 解析結查語句(string sql) {
結查表 table;//sql解析
// 省略實作
table.name = "Person";//名字
table.列 = [
結查列("id", "INTEGER"),
結查列("name", "TEXT"),
結查列("birthday", "DATE"),
];
return table;
}//這是解析sql剩下的
//先分解,插件模闆聲明+取串
mixin template 結查表對象(string sql) {//@2
// sql轉D,編譯時轉換
template 結查變量類型(string 結查類型) {
static if(結查類型 == "INTEGER")
alias 結查變量類型 = int;
else static if(結查類型 == "DATE") {
import std.datetime;
alias 結查變量類型 = Date;
} else static if(結查類型 == "TEXT")
alias 結查變量類型 = string;
else static assert(0, "未知類型" ~ 結查類型);
}//變量類型轉換
// 使用者定義反射
struct 結查列 {
string name;
}//重要的是結查表.
// 生成變量,一次一個,用小串插件
mixin template 結查變量(結查列[]列){//重點在此
mixin("
//自定義屬性,用于反射
@結查列(列[0].name)
//串中有類型轉換,用遞歸
結查變量類型!(列[0].type) " ~ 列[0].name ~ ";");//第一個在這裡.
static if(列.length > 1)
mixin 結查變量!(列[1 .. $]);
}//一堆變量,這裡沒有定義結果列第一個變量.
// 普通聲明加變量插件
class 我們結查表對象 {
//待加變量
mixin 結查變量!(解析結查語句(sql).列);
//這裡插入變量
void save() {//儲存函數
import std.stdio;
import std.traits;
//用反射檢視生成的東西
foreach(idx, variable; getSymbolsByUDA!(我們結查表對象, 結查列)) {
auto name = getSymbolsByUDA!(我們結查表對象, 結查列)[idx].stringof;
writeln(name, " = ", variable);
}//檢視
}
}
// 串插件中再用别名來取名字
mixin("alias " ~ 解析結查語句(sql).name ~ " = 我們結查表對象;");//用别名來定義我們的類.
}
//混合所有,搞定
mixin 結查表對象!(sql);//@1
void main() {
auto person = new Person;
person.id = 10;
person.save();
}