原文在此
还有一篇
还有这里
还有这里都可以看看.元编程相关的.
我们想要:
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();
}
几行串插件
,搞定一切.