我想要一种将对象序列化和反序列化为JSON的方法,尽可能自动。
Serialize:对我来说,理想的方式是,如果我调用一个实例JSONSerialize(),它会返回一个带有JSON对象的字符串,该对象的所有公共属性都是< code >“name _ of _ property”:“value”。对于那些基本类型的值,这很简单,对于对象,它应该尝试在每个JSONSerialize()或ToString()或类似的对象上调用,以递归地序列化所有的公共属性。对于集合,它也应该正确运行(只有向量/数组是可以的)。
反序列化:只需创建给定对象的实例(比如狗)并调用JSONDeserialize(json_string)
,这应该填充所有公共属性,创建所需的对象,以防属性不是原语或所需的集合。
一个例子应该这样运行:
Dog *d1 = new Dog();
d1->name = "myDog";
string serialized = d1->JSONSerialize();
Dog *d2 = new Dog();
d2->JSONDeserialize(serialized);
std::cout << d2->name; // This will print "myDog"
或者像这样:
Dog *d1 = new Dog();
d1->name = "myDog";
string serialized = JSONSerializer.Serialize(d1);
Dog *d2 = JSONSerializer.Deserialize(serialized, Dog);
std::cout << d2->name; // This will print "myDog"
我怎样才能轻松地完成这件事?
有没有像这样简单的东西存在??谢谢:))
C 不将类成员名称存储在已编译的代码中,并且无法(在运行时)发现类包含哪些成员(变量/方法)。换句话说,您不能循环访问结构的成员。由于没有这样的机制,因此无法为每个对象自动创建“JSONserialize”。
但是,您可以使用任何 json 库来序列化对象,但您必须自己为每个类编写序列化/反序列化代码。要么这样,要么你必须创建类似于QVariantMap的可序列化类,这些类将用于而不是所有可序列化对象的结构。
换言之,如果您对所有可序列化对象使用特定类型(或为每个类自己编写序列化例程)感到满意,就可以这样做。然而,如果你想自动序列化每个可能的类,你应该忘记它。如果此功能对您很重要,请尝试其他语言。
为此,你需要C/C中的反射,这是不存在的。你需要一些元数据来描述你的类的结构(成员,继承的基类)。目前,C/C编译器不会在构建的二进制文件中自动提供这些信息。
我也有同样的想法,我使用GCC XML项目来获取此信息。它输出描述类结构的 XML 数据。我已经建立了一个项目,我正在解释这个页面中的一些关键点:
序列化很容易,但我们必须处理复杂的数据结构实现(例如,std::string,std:::map),这些实现与分配的缓冲区有关。反序列化更复杂,您需要重建对象及其所有成员,再加上对vtables的引用……这是一个痛苦的实现。
例如,您可以像这样序列化:
// Random class initialization
com::class1* aObject = new com::class1();
for (int i=0; i<10; i++){
aObject->setData(i,i);
}
aObject->pdata = new char[7];
for (int i=0; i<7; i++){
aObject->pdata[i] = 7-i;
}
// dictionary initialization
cjson::dictionary aDict("./data/dictionary.xml");
// json transformation
std::string aJson = aDict.toJson<com::class1>(aObject);
// print encoded class
cout << aJson << std::endl ;
要反序列化数据,它的工作原理如下:
// decode the object
com::class1* aDecodedObject = aDict.fromJson<com::class1>(aJson);
// modify data
aDecodedObject->setData(4,22);
// json transformation
aJson = aDict.toJson<com::class1>(aDecodedObject);
// print encoded class
cout << aJson << std::endl ;
盎司:
>:~/cjson$ ./main
{"_index":54,"_inner": {"_ident":"test","pi":3.141593},"_name":"first","com::class0::_type":"type","com::class0::data":[0,1,2,3,4,5,6,7,8,9],"com::classb::_ref":"ref","com::classm1::_type":"typem1","com::classm1::pdata":[7,6,5,4,3,2,1]}
{"_index":54,"_inner":{"_ident":"test","pi":3.141593},"_name":"first","com::class0::_type":"type","com::class0::data":[0,1,2,3,22,5,6,7,8,9],"com::classb::_ref":"ref","com::classm1::_type":"typem1","com::classm1::pdata":[7,6,5,4,3,2,1]}
>:~/cjson$
通常这些实现依赖于编译器(例如ABI规范),并且需要外部描述才能工作(GCCXML输出),因此不容易集成到项目中。
C中没有反射。但是,如果编译器不能为您提供所需的元数据,您可以自己提供。
让我们从创建属性结构开始:
template<typename Class, typename T>
struct PropertyImpl {
constexpr PropertyImpl(T Class::*aMember, const char* aName) : member{aMember}, name{aName} {}
using Type = T;
T Class::*member;
const char* name;
};
template<typename Class, typename T>
constexpr auto property(T Class::*member, const char* name) {
return PropertyImpl<Class, T>{member, name};
}
当然,您也可以有一个<code>属性</code>,它接受一个setter和getter,而不是指向成员的指针,还可以是您想要序列化的计算值的只读属性。如果您使用C17,您可以进一步扩展它,使其成为一个可用于lambdas的属性。
好的,现在我们有了编译时自省系统的构建块。
现在在您的类< code>Dog中,添加您的元数据:
struct Dog {
std::string barkType;
std::string color;
int weight = 0;
bool operator==(const Dog& rhs) const {
return std::tie(barkType, color, weight) == std::tie(rhs.barkType, rhs.color, rhs.weight);
}
constexpr static auto properties = std::make_tuple(
property(&Dog::barkType, "barkType"),
property(&Dog::color, "color"),
property(&Dog::weight, "weight")
);
};
我们需要对该列表进行迭代。要迭代元组,有很多方法,但我最喜欢的一种是:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
using unpack_t = int[];
(void)unpack_t{(static_cast<void>(f(std::integral_constant<T, S>{})), 0)..., 0};
}
如果编译器中有C 17折叠表达式,那么< code>for_sequence可以简化为:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
这将为整数序列中的每个常量调用一个函数。
如果这个方法不起作用或者给你的编译器带来麻烦,你总是可以使用数组扩展的技巧。
现在您已经有了所需的元数据和工具,您可以遍历属性来取消序列化:
// unserialize function
template<typename T>
T fromJson(const Json::Value& data) {
T object;
// We first get the number of properties
constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
// We iterate on the index sequence of size `nbProperties`
for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i) {
// get the property
constexpr auto property = std::get<i>(T::properties);
// get the type of the property
using Type = typename decltype(property)::Type;
// set the value to the member
// you can also replace `asAny` by `fromJson` to recursively serialize
object.*(property.member) = Json::asAny<Type>(data[property.name]);
});
return object;
}
对于序列化:
template<typename T>
Json::Value toJson(const T& object) {
Json::Value data;
// We first get the number of properties
constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
// We iterate on the index sequence of size `nbProperties`
for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i) {
// get the property
constexpr auto property = std::get<i>(T::properties);
// set the value to the member
data[property.name] = object.*(property.member);
});
return data;
}
如果您想要递归序列化和反序列化,您可以将asany
替换为fromJson
。
现在您可以像这样使用您的函数:
Dog dog;
dog.color = "green";
dog.barkType = "whaf";
dog.weight = 30;
Json::Value jsonDog = toJson(dog); // produces {"color":"green", "barkType":"whaf", "weight": 30}
auto dog2 = fromJson<Dog>(jsonDog);
std::cout << std::boolalpha << (dog == dog2) << std::endl; // pass the test, both dog are equal!
做!无需运行时反射,只需一些C 14的优点!
这段代码可以从一些改进中受益,当然可以通过一些调整与C 11一起使用。
请注意,您需要编写< code>asAny函数。它只是一个函数,接受一个< code>Json::Value并调用正确的< code >作为...函数,或者另一个< code>fromJson。
下面是一个完整的工作示例,该示例由此答案的各种代码片段组成。随意使用它。
正如评论中提到的,这段代码不能在msvc上运行。如果您想要一个兼容的代码,请参考这个问题:指向成员的指针:在GCC中有效,但在VS2015中无效
所有包 | 方法 包 system.web.helpers 继承 class CJSON 源自 1.0 版本 $Id: CJSON.php 3204 2011-05-05 21:36:32Z alexander.makarow $ 源码 framework/web/helpers/CJSON.phpCJSON用于转换PHP数据到JSON格式基从JSON格式转换为PHP数据。 公共方法 隐藏继承方法
python-cjson 是一个适用于 Python 的快速 JSON 编码器/解码器。 JSON代表JavaScript Object Notation,它是一种基于文本的轻量级数据交换格式,易于人类读取/写入以及易于机器解析/生成。JSON完全独立于语言,并且在大多数编程语言中都有多种实现,使其成为数据交换和存储的理想选择。 该模块是用 C 编写的,与其他直接用python编写的python
Lua CJSON 为 Lua 语言提供高性能的 JSON 解析器和编码器,其性能比纯 Lua 库要高 10 到 20 倍。Lua CJSON 完全支持 UTF-8 ,无需依赖其他非 Lua/LuaJIT 的相关包。
php-cjson 是快速的 JSON 解析和生成的 PHP 库,基于 cjson 底层 C 库开发。 安装 $/path/to/phpize$./configure --with-php-config=/path/to/php-config$make && make install 示例 encode $arr = array( 1, "string", array("key"
cJSON-plus基于cJSON的功能扩展库。主要适用于非强交互场景,如终端操作,要使用到cJSON处理json数据。如果你有协议数据模板,使用该库可以减少很多业务逻辑的设计,减少代码的冗余。 cJSON-plus里面包含了一些基于cJSON而实现的函数。 例如: 向前添加键值对。 修改指定域的字符串。 遍历cJSON对象。 其他格式化输出对象。(支持列表和树形等) 遍历修改所有项功能。 修改指
Lua CJSON is a Lua C module that provides fast JSON parsing and encoding support for Lua. Project homepage: http://www.kyne.com.au/~mark/software/lua-cjson.php OpenResty includes its own fork of this
我正在尝试使用kryo序列化和反序列化到二进制。我想我已经完成了序列化,但似乎无法反序列化。下面是我正在处理的代码,但最终我想存储一个字节[],然后再次读取它。文档只显示了如何使用文件。
问题内容: 我尝试过在Java和Android之间实现跨平台序列化。我使用了Serializable,并将我的代码在Android中与台式机Java放在同一软件包中。 来源:java-desktop序列化 资料来源:Android-反序列化 学生是一类,实现了Serializable。在桌面上,我将学生实例序列化为“ thestudent.dat”。我将此文件放在Android设备上的SD卡上,并