原文
D
中用定属
可以为构/原始类型/编译时执行函数(返回值)
.
用@TypeName
附加,用__traits(getAttributes)
来取用定属
.
enum AnEnum{a} struct AStruct{} class AClass{} int FunctionThatReturnsTheUDAValue(){ return 0; } @AnEnum @AStruct @AClass @FunctionThatReturnsTheUDAValue struct Test{} void main() { import std.traits; // __traits(getAttributes)返回符号上的所有`用定属`元组 static foreach(uda; __traits(getAttributes, Test)) pragma(msg, uda); /* 输出: AnEnum AStruct AClass 0 */ }
还有std.traits#hasUDA和std.traits#getUDAs
,来有/取
用定属.std.traits#getSymbolsByUDA
这个也很方便.
struct UsefulUDA { string some; int data; } struct NeverUsedUDA { } struct MultiUDA { string data; } @UsefulUDA("Foo", 21) @MultiUDA("Use") @MultiUDA("Me") @(MultiUDA("Multiple"), MultiUDA("Times")) struct MyStruct { } void main() { import std.traits : hasUDA, getUDAs; import std.stdio : writeln, write; writeln("构有@UsefulUDA?: ", hasUDA!(MyStruct, UsefulUDA)); writeln("@NeverUsedUDA呢?: ", hasUDA!(MyStruct, NeverUsedUDA)); // 可多次用UDAs,getUDAs返回所有. const UsefulUDA useful = getUDAs!(MyStruct, UsefulUDA)[0];//要用[0]取第1个. writeln(useful); // 多次遍历 static foreach(uda; getUDAs!(MyStruct, MultiUDA)) write(uda.data, " "); /* 输出: 构有@UsefulUDA?: true @NeverUsedUDA呢?: false const(UsefulUDA)("Foo", 21) Use Me Multiple Times */ }
我们用如下三个
属性来更新序化器
.
属性 | 意思 |
---|---|
@Ignore | 忽略字段 |
@Name | 自定义名字 |
@ByValue | 按值序化 枚举,而非名字 . |
我们用构
来表示用定属
.
struct ByValue {} struct Ignore {} struct Name { string name; } // 保留`Person`,用它来比较`用定属`的输出 struct Person { string name; int age; PersonType type; } struct PersonWithUDAs {//带用定属的人. @Ignore string name; @Name("yearsOld") int age; @ByValue PersonType type; }
由于静每一(a)
的展开
.a
与下
的合作不是很好.因而,得有点技巧.我们把静每一
锁在检查是否忽略
字段的静如
之后.如下在序化构/类
的{{}}
:
static foreach(member; T.tupleof) {{ alias MemberType = typeof(member); const MemberName = __traits(identifier, member); MemberType memberValue = mixin("value." ~ MemberName); //静每一,如果`没有`忽略字段. static if(!hasUDA!(member, Ignore)) { toReturn[MemberName] = serialise(memberValue); } }}
同样:反序化
中这样:
static foreach(member; T.tupleof) {{ alias MemberType = typeof(member); const MemberName = __traits(identifier, member); static if(!hasUDA!(member, Ignore)) //但对大块代码,这很烦人.因为不能用`下`. { MemberType memberValue = deserialise!MemberType(json[MemberName]); mixin("toReturn." ~ MemberName ~ " = memberValue;"); } }}
目前
还没有@名
字段.
static if(!hasUDA!(member, Ignore)) {//修改该函数内容为 JSONValue serialised = serialise(memberValue); //存储在变量中,供未来用. static if(hasUDA!(member, Name)) //需要时,用自定义名 { const SerialiseName = getUDAs!(member, Name)[0].name; toReturn[SerialiseName] = serialised; } else // 否则用`字段名` { toReturn[MemberName] = serialised; } }
反序化:
static if(!hasUDA!(member, Ignore)) {//修改这个块. static if(hasUDA!(member, Name)) {//名字 const SerialiseName = getUDAs!(member, Name)[0].name; JSONValue value = json[SerialiseName]; } else { JSONValue value = json[MemberName]; } MemberType memberValue = deserialise!MemberType(value); mixin("toReturn." ~ MemberName ~ " = memberValue;"); }
按值
:
//注意,在`忽略`中. static if(!hasUDA!(member, Ignore)) { // 存储进变量 static if(hasUDA!(member, ByValue) && is(MemberType == enum)) {//按值. JSONValue serialised = JSONValue(memberValue); } else {//按名 JSONValue serialised = serialise(memberValue); } static if(hasUDA!(member, Name)) {//名字 const SerialiseName = getUDAs!(member, Name)[0].name; toReturn[SerialiseName] = serialised; } else { toReturn[MemberName] = serialised; } }
同样反序化
:
static if(!hasUDA!(member, Ignore)) {//忽略 static if(hasUDA!(member, Name)) {//名字 const SerialiseName = getUDAs!(member, Name)[0].name; JSONValue value = json[SerialiseName]; } else { JSONValue value = json[MemberName]; } // 不能再用`解序化`了.因为假定`按名字串`存储枚. static if(hasUDA!(member, ByValue)) { MemberType memberValue = value.integer.to!MemberType(); }//转为成员类型. else { MemberType memberValue = deserialise!MemberType(value); } mixin("toReturn." ~ MemberName ~ " = memberValue;"); }
测试代码:
void main() { import std.stdio : writeln; auto person = Person("Bradley", 20, PersonType.Student); auto personUDA = PersonWithUDAs("Bradley", 20, PersonType.Student); writeln(person.serialise()); writeln(personUDA.serialise()); writeln(person.serialise().deserialise!Person()); writeln(personUDA.serialise().deserialise!PersonWithUDAs()); /* 输出: {"age":20,"name":"Bradley","type":"Student"} {"type":1,"yearsOld":20} Person("Bradley", 20, Student) PersonWithUDAs("", 20, Student) */ }
随着用定属
的添加,代码越复杂
.要合理组织好.