C++自動(dòng)序列化和反序列化在實(shí)際軟件開(kāi)發(fā)中的應(yīng)用(二)

上一篇文章介紹了自動(dòng)進(jìn)行序列化和反序列化的方法沈条,其中也指出了其中存在的問(wèn)題以及不足综苔,今天這篇文章來(lái)詳細(xì)說(shuō)下如何處理

背景

目前使用自動(dòng)生成屬性的方法支持的數(shù)據(jù)類(lèi)型有限,并不是所有的數(shù)據(jù)類(lèi)型有支持,不支持的類(lèi)型生成的鍵值對(duì)的值會(huì)是 null逼泣,肯定不是我們想要的,因此需要對(duì)這些類(lèi)型進(jìn)行自定義擴(kuò)展舟舒。

目前不支持的類(lèi)型主要有以下幾種場(chǎng)景:

  • QRect
  • QSize
  • QPoint
  • QList<T>拉庶,QVector<T>,比如: QList<int>秃励,QList<float>氏仗,QList<double>……
  • QPolygon, QPolygonF
  • QLine,QLineF
  • QMap, QSet,QHash……
  • std 標(biāo)準(zhǔn)庫(kù)數(shù)據(jù)類(lèi)型
  • 其它自定義類(lèi)型

原因

為什么上述類(lèi)型不支持呢莺治?有兩個(gè)原因:

第一廓鞠,上述這些類(lèi)型無(wú)法反向解析,無(wú)法進(jìn)行有效的區(qū)分谣旁,比如你想把一個(gè)QSize 保存成什么樣子床佳?

  • 數(shù)組形式:[10,10]
  • 字符串:"QSize(10,10)"

不管哪種方式,都不是通用的榄审,數(shù)組格式在反序列化時(shí)無(wú)法還原砌们,除非手動(dòng)進(jìn)行,字符串方式有冗余字段無(wú)法滿(mǎn)足三方使用搁进。

第二浪感,其實(shí)不怪 QtJSON 的鍵值就支持這些類(lèi)型,[侯捷] 曾說(shuō)過(guò)「源碼面前了無(wú)秘密」,我們?cè)夙槺憧聪?code>Qt源碼饼问。

某個(gè)字段的值是這樣獲取的影兽,返回的是一個(gè) QVariant 類(lèi)型,這個(gè)類(lèi)型本身可以支持多種數(shù)據(jù)類(lèi)型

QVariant v = object->property(proName);

將獲取的鍵值插入到 QJsonObject 當(dāng)中:

jsObj.insert(proName, QJsonValue::fromVariant(v));

問(wèn)題就出在這里莱革,JSON 對(duì)象的值需要一個(gè) QJsonValue 類(lèi)型峻堰,但是 QJsonValue 僅僅支持常見(jiàn)的基本數(shù)據(jù)類(lèi)型

    QJsonValue(Type = Null);
    QJsonValue(bool b);
    QJsonValue(double n);
    QJsonValue(int n);
    QJsonValue(qint64 v);
    QJsonValue(const QString &s);
    QJsonValue(QLatin1String s);
    QJsonValue(const QJsonArray &a);
    QJsonValue(const QJsonObject &o);

基于上述兩個(gè)原因讹开,我們能夠做的只能是把其它類(lèi)型轉(zhuǎn)換成標(biāo)準(zhǔn)JSON 支持的類(lèi)型。

方案

JSON作為通用的數(shù)據(jù)格式捐名,一般普遍做法需要針對(duì)特殊類(lèi)型字段單獨(dú)處理旦万,再反序列化時(shí)也需要單獨(dú)處理,下面以QPoint镶蹋、QSize 兩種類(lèi)型為例詳細(xì)展開(kāi)說(shuō)下:

    Q_PROPERTY(QSize testSize READ testSize WRITE setTestSize)
    Q_PROPERTY(QPoint testPoint READ testPoint WRITE setTestPoint)

在進(jìn)行序列化時(shí)成艘,判斷該屬性類(lèi)型,然后分別進(jìn)行處理:

    switch (propertyType)
    {
    case QMetaType::QSize:      return serializeSize(value.toSize());
    case QMetaType::QSizeF:     return serializeSize(value.toSizeF());
    default:                    throw  KException{ QByteArray("Invalid type id ") +
                         QByteArray(QMetaType::typeName(propertyType))};
    }

QSize和QSizeF 是類(lèi)似的贺归,因此需要寫(xiě)一個(gè)模板來(lái)統(tǒng)一處理:

template <class Size>
static inline QVariant serializeSize(const Size &size)
{
    return QVariant(QJsonArray{size.width(), size.height()});
}

擴(kuò)展

一般我們能想到的是分別實(shí)現(xiàn)對(duì)QSizeQSizeF 進(jìn)行處理淆两,這個(gè)時(shí)候你會(huì)寫(xiě)兩個(gè)函數(shù)來(lái)處理,進(jìn)階后你會(huì)寫(xiě)一個(gè)模板來(lái)處理拂酣,那么再次進(jìn)階下琼腔,怎么處理呢?

來(lái)看一個(gè)更高級(jí)的用法(語(yǔ)法糖踱葛,C++17才有的)

QJsonValue serializeSize(const std::variant<QSize, QSizeF> &size) const
{
    return
        std::visit([](const auto &s) -> QJsonArray {
            return {s.width(), s.height()};
        }, size);
}

上述代碼可以參考開(kāi)源項(xiàng)目: https://github.com/Skycoder42/QtJsonSerializer

總結(jié)

上述提供了一種方案和思路丹莲,按照這個(gè)思路繼續(xù)擴(kuò)展其它數(shù)據(jù)類(lèi)型即可,如果感興趣可以直接看這個(gè)開(kāi)源項(xiàng)目:https://github.com/Skycoder42/QtJsonSerializer尸诽, 不過(guò)需要 Qt5.12 及以上版本才支持哦

如果想自己動(dòng)手實(shí)現(xiàn)甥材,順便深入學(xué)習(xí)下 Qt 元對(duì)象系統(tǒng),那么可以一起參與進(jìn)來(lái)性含,從零實(shí)現(xiàn)一個(gè)簡(jiǎn)易版本的序列化庫(kù): https://github.com/kevinlq/KSerialize.

授人以魚(yú)不如授人以漁洲赵, 方案和思路有了,關(guān)鍵還是要多動(dòng)手寫(xiě)起來(lái),如果有問(wèn)題隨時(shí)留言交流商蕴。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叠萍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绪商,更是在濱河造成了極大的恐慌苛谷,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件格郁,死亡現(xiàn)場(chǎng)離奇詭異腹殿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)例书,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)锣尉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人决采,你說(shuō)我怎么就攤上這事自沧。” “怎么了树瞭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵拇厢,是天一觀的道長(zhǎng)筏勒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)旺嬉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任厨埋,我火速辦了婚禮邪媳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荡陷。我一直安慰自己雨效,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布废赞。 她就那樣靜靜地躺著徽龟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唉地。 梳的紋絲不亂的頭發(fā)上据悔,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音耘沼,去河邊找鬼极颓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛群嗤,可吹牛的內(nèi)容都是我干的菠隆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狂秘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼骇径!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起者春,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤破衔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后钱烟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體运敢,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年忠售,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了传惠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稻扬,死狀恐怖卦方,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泰佳,我是刑警寧澤盼砍,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布尘吗,位于F島的核電站,受9級(jí)特大地震影響浇坐,放射性物質(zhì)發(fā)生泄漏睬捶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一近刘、第九天 我趴在偏房一處隱蔽的房頂上張望擒贸。 院中可真熱鬧,春花似錦觉渴、人聲如沸介劫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)座韵。三九已至,卻和暖如春踢京,著一層夾襖步出監(jiān)牢的瞬間誉碴,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工瓣距, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翔烁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓旨涝,卻偏偏與公主長(zhǎng)得像蹬屹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子白华,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容