Serialization 如何简化反序列化框架?

Serialization 如何简化反序列化框架?,serialization,d,Serialization,D,我有一个序列化接口,用于封装我的应用程序的XML/JSON/二进制序列化之间的差异。它看起来像这样: interface Serialization { bool isObject(); int opApply(int delegate(string member, Serialization value) del); //iterate object ... int toInt(); //this part is ugly, but without temp

我有一个序列化接口,用于封装我的应用程序的XML/JSON/二进制序列化之间的差异。它看起来像这样:

interface Serialization {
    bool isObject();
    int opApply(int delegate(string member, Serialization value) del); //iterate object
    ...
    int toInt();   //this part is ugly, but without template member overloading, I
    long toLong(); //figure out any way to apply generics here, so all basic types
    ...            //have a toType primitive
    string toString();
}
class JSONSerialization : Serialization {
    private JSON json;
    ...
    long toLong() {
        enforce(json.type == JSON_TYPE.NUMBER, SerializationException.IncorrectType);
        return cast(long)json.toNumber();
    }
    ...
}
auto _readFrom(T)(string s){
    static if(__traits(compiles,(readf("",cast(T*)(null))))){
        T result;
        formattedRead(s,"%s",&result);
        return result;
    }else{
        return T.readFrom(s);
    }
}
因此,我随后设置了一组模板,用于注册类型反序列化器并调用它们:

...
registerTypeDeserializer!Vec3(delegate Vec3(Serialization s) {
    return Vec3(s[0].toFloat, s[1].toFloat, s[2].toFloat);
});
...
auto v = parseJSON("some file").deserialize!Vec3;
...
registerTypeDeserializer!Light(delegate Light(Serialization s) {
    return new Light(s["intensity"].toFloat, s["position"].deserialize!Vec3);
});
这适用于结构和简单类,使用新的参数标识符元组和参数默认值元组,我甚至可以添加自动反序列化器生成。但是,我并不喜欢基本类型和用户定义类型之间的不一致性,更重要的是,复杂类型必须依赖全局状态来获取引用:

static MaterialLibrary materials;
registerTypeDeserializer!Model(delegate Model(Serialization s) {
    return new Model(materials.borrow(s["material"].toString), ...);
});
这就是它真正崩溃的地方。因为我不能(在没有大量寄存器反序列化器函数的情况下)将其他参数传递给反序列化器,所以我很难避免丑陋的全局工厂。我曾考虑过取消反序列化模板,并为每个用户定义的类型要求一个反序列化函数(可以接受多个参数),但对于POD结构来说,这似乎是一个很大的工作


那么,我如何简化这个设计,并希望避免大量的样板反序列化程序,同时仍然允许我适当地注入对象工厂,而不是全局分配它们呢?

基本类型可以使用
readf
\
formattedRead
<,因此,您可以尽可能创建一个使用此
formattedRead
的包装函数,否则它将使用所需类型的静态函数来读取值。大概是这样的:

interface Serialization {
    bool isObject();
    int opApply(int delegate(string member, Serialization value) del); //iterate object
    ...
    int toInt();   //this part is ugly, but without template member overloading, I
    long toLong(); //figure out any way to apply generics here, so all basic types
    ...            //have a toType primitive
    string toString();
}
class JSONSerialization : Serialization {
    private JSON json;
    ...
    long toLong() {
        enforce(json.type == JSON_TYPE.NUMBER, SerializationException.IncorrectType);
        return cast(long)json.toNumber();
    }
    ...
}
auto _readFrom(T)(string s){
    static if(__traits(compiles,(readf("",cast(T*)(null))))){
        T result;
        formattedRead(s,"%s",&result);
        return result;
    }else{
        return T.readFrom(s);
    }
}

谢谢你的回复。实际上,我在解析这些值时没有遇到任何问题。目前我正在使用std.conv读入JSON对象树,但将来我希望能够使用自定义二进制格式,从而使序列化接口抽象出序列化格式的细节。我正在努力解决的是如何管理那些“所需类型的静态函数”,特别是在存在创建依赖项的情况下。如果我使用一个模板来同质化所有反序列化器函数,我如何向它们传递支持参数?为什么首先要传递额外的序列化参数?对象的序列化字符串需要保存所有信息才能重新创建对象。因为我的某些类型包含对它们不拥有的对象的引用,例如模型/材质示例。材质将在多个模型之间共享,因此模型的反序列化器需要能够从集合中检索正确的材质,而不是创建新的材质。该集合(MaterialLibrary)必须是全局的,或者传递给反序列化程序。好吧,这样做如何:静态
readForm
函数将不会获得
字符串作为其参数-它们将获得一个
反序列化
对象。该
反序列化
对象除了传递要反序列化的字符串的下一部分外,还将存储所有已反序列化的对象(使用某种键)。需要访问该信息的反序列化静态函数将能够做到这一点,而不需要该信息的函数(独立对象)将不会受到额外信息的干扰,因为它们只获得指向对象的指针。哈!我想就是这样。事实上,我已经在传递序列化,它基本上是一个对象树。因此,根据您的想法,当我反序列化一个对象的main部分时,我只需要用序列化包装器替换树中对该对象的引用。谢谢你,伊丹!我认为这有很大的潜力。