2

我正在尝试更多地了解 D 的编译时评估,并了解它的模板、mixin、属性等是如何工作的。我想做的一件事是找出一种优雅的方法来将类的成员标记为可序列化或可从数据库加载。在下面的示例中,我创建了一个元组,其中列出了在读取或(稍后)序列化实例时要使用的成员。

我的第一个问题是,如下所示,这是对元组的正确用法吗?其次,如果是这样,有没有办法在编译时使用我分配给相关成员变量的用户定义属性自动生成这个元组?我已经浏览了各种文档页面,例如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
}
4

2 回答 2

1

这不是一个很好的答案,但我通过定义自己的帮助模板并将结构用作 UDA(其值指示参数)来使用它们。帮助模板在这里:

https://github.com/Cyber​​Shadow/ae/blob/master/utils/meta.d#L133

它们在这里使用,以允许覆盖 JSON 序列化器/反序列化器的 JSON 字段:

https://github.com/Cyber​​Shadow/ae/blob/master/utils/json.d#L505

于 2013-01-09T15:33:53.870 回答
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]);
        }
    }
}
于 2013-01-17T16:21:15.940 回答