设为首页 加入收藏

TOP

从RPC开始(二)、序列化(二)
2017-10-13 10:39:17 】 浏览:813
Tags:RPC 开始 序列化
,我们不能够容忍这样的“无聊”;因为我们可以进行类型萃取:

  1、如果为基本类型,我们直接保存其二进制值;

  2、如果其为自定义类,且有成员函数“serialize/deserialize”,我们通过调用该配套函数进行序列化和反序列化;

  3、如果其为自定义类,且是POD,同样直接保存其二进制值;

  4、以上的其他情况,编译器会直接报错。

  以上方案,可以通过C++11完成。至于方式,其涉及模板元编程;我并不详细描述,大致通过以下方式完成:

  1、使用TypeList定义基本类型的类型列表(当然可以逐个特化,但这样失去了味道),以判断是否为基本类型;

  2、使用C++11的decltype判断是否有“serialize/deserialize”成员函数;

  3、在类型信息中查找该类型是否为POD且不为指针。

  然后,使用元编程将以上3个信息融合得到最佳的选择。详细的,可以参考未来的某天,我将要讲的《基于C++11的类型系统》。或者,可以依次搜索:泛型编程与设计模式之应用(TypeList)、C++SFINAE(关键技术decltype)、STL的type_traits。

  有一个关键的地方不得不提:不为指针。是的,我没有支持指针的序列化;因为,我们并不能够知道一个指针是一个元素还是一个数组。当然,我们可以支持shared_ptr和vector,以更健壮的方式。

  总结一下,在你学完所有以上提到的及术后,我们便能够创建出以下序列化方式:

  1、基本类型和自定义POD调用以下方式:

template<typename T>
void _Serialize(IBuffer* buffer, const T& val)
{
    buffer->write((const byte*)&val, sizeof(T));
}

template<typename T>
bool _Deserialize(IBuffer* buffer, T& val)
{
    return buffer->read((byte*)&val, sizeof(T));
}

  2、自定义类型且有配套函数:

template<typename T>
void _Serialize(IBuffer* buffer, const T& val)
{
    val.serialize(buffer);
}

template<typename T>
bool _Deserialize(IBuffer* buffer, T& val)
{
    return val.deserialize(buffer);
}

  还有一个问题就是,对于已完善的不可更改类的处理:很简单和自然,重载以上_Serialize/_Deserialize函数;比如STL中的std::string就需要如此处理。

  还有一个不可忽视的问题:健壮性!也就是,我们需要感知类型,我们需要类型信息。很自然的方式,我们在序列化时写入类型信息;在反序列化首先获取该信息,并判断是否类型匹配。

  可用的方式是:写入类型ID;通常来说是一个字符串。但,问题的关键是谁来生成并提供这个字符串?

  自然,依然使用C++的方式:模板特化

template<>
struct TypeInfo<Something>{
    static std::string Name(){ return "Something";}
};

  这种方式,很繁琐,意味着:对于每一个需要序列化的类型,我们都需要特化一个模板!但,这是必不可少的,因为我们没有完整的运行时类型系统,我们可以操作类型的唯一机会,只在编译期。不要抱怨,每个类,也只需要一次而已,代价并不高。

 

  完了。?没有,这个“判断过程”由谁来做?绝不是手动进行。到这里,我们需要引入一个“代理”:Any,可变类型。也就是,其可以包装所有类型;然后通过模板函数来获取值:

template<typename T>
void Any::from(const T& val);

template<typename T>
T& Any::to();

template<typename T>
const T& Any::to()const;

  在序列化时,我们需要首先将类型包装到Any中,然后通过Any执行序列化;在另一端,我们将Buffer交给Any然后再调用to<T>()时反序列化;这时,我们就有一个中间层帮我们完成类型信息的写入和匹配:

void _AnyData::serialize(IBuffer* buffer)
{
    Serialize(buffer, TypeInfo<T>::Name());
    Serialize(buffer, mData);
}

bool _AnyData::deserialize(IBuffer* buffer)
{
    std::string name;
    if(!Deserialize(buffer, name)){
        return false;
    }
  if(name != TypeInfo<T>::Name()){
    return false;
  }
return Deserialize(buffer, mData); }

  当然,以上仅仅是示例并非可用的代码;但,也差不多了。这样,我们便能够完成序列化和反序列化的完整操作,并且在安全的环境下。当然需要说明一下所谓的安全:是指我们能够感知错误的反序列化,并有机会进行相应的处理。Deserialize返回布尔值,便是作为一个通知(我并没有选择抛出异常)。

 

  以上,便是序列化框架的所有了;当然,并没有列出所有的内容;但也,足够说明,C++能够以我的方式构造出一个相对安全且可用的序列化。

  PS:很多东西,我并没有展开;有机会的话,可以等开源我的代码;但很渺茫。

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【原创】起步互联网公司内部短信.. 下一篇抽象工厂模式(13)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目