QVariant 反序列化给出无效值

Posted

技术标签:

【中文标题】QVariant 反序列化给出无效值【英文标题】:QVariant deserialization gives invalid value 【发布时间】:2020-02-20 13:29:10 【问题描述】:

我有以下类要序列化和反序列化:

#include <QObject>
#include <QDataStream>
#include <QVariant>

/**
 * @brief   The type used to store the \ref CComPacket::Cmd enum
 */
using CmdType = quint8;

/**
 * @brief   A smart container for the TCP packets
 */
class CComPacket : public QObject

    Q_OBJECT

public:

    /**
     * @brief   Provides the command information for the packet (tells how
     *          the data is supposed to be parsed).
     */
    enum class Cmd: CmdType
    
        Invalid,
        ReadName,
        GiveName,
    ;

    explicit CComPacket(QObject *parent = nullptr);

    /**
     * @brief   The ostream (<<) overloading
     * @param   out: The data stream to which the \p cpp class is going to
     *          be serialized.
     * @param   ccp: the class to be serialized into the \p out.
     * @return  reference to \p out.
     */
    friend QDataStream& operator<<(QDataStream& out, const CComPacket& ccp)
    
        out << static_cast<CmdType>(ccp.m_cmd) << ccp.m_data;
        return out;
    

    /**
     * @brief   The istream (>>) overloading
     * @param   in: The serialized data that will be deserialized to the \p cpp
     * @param   ccp: deserialized data goes here.
     * @return  The \p in reference.
     */
    friend QDataStream& operator>>(QDataStream& in, CComPacket& ccp)
    
        CmdType tmp;
        in >> tmp >> ccp.m_data;
        ccp.m_cmd = static_cast<Cmd>(tmp);

        return in;
    

    /**
     * @brief   The parsing command
     */
    Cmd m_cmd = Cmd::Invalid;

    /**
     * @brief   The data to be parsed
     */
    QVariant m_data;

;

我正在尝试使用此代码进行测试:

CComPacket tmp;
tmp.m_cmd = CComPacket::Cmd::GiveName;
tmp.m_data = 5.112233;

QDataStream str;
str << tmp;

CComPacket tmp2;
str >> tmp2;

调试时我看到tmp2m_cmd 成员被正确反序列化,但m_data 对象仍然无效。从文档中我了解到QVariant 默认支持序列化。我在这里错过了什么?

【问题讨论】:

在您的测试代码中,您有 QDataStream str 在没有设备上运行,因此它无法工作。这只是这个例子中的疏忽还是真正的代码? 这是实际代码。正如我在回答中提到的那样,我忘记为流提供实际的缓冲区。谢谢。 【参考方案1】:

为了完成这项工作,我必须合并必须用作QDataStream 参数的QByteArray,因为已经需要一个物理容器。我计划在后面的步骤中将数据序列化为字节,所以这让一切变得更容易。我添加了以下成员函数:

QByteArray serialize();
static CComPacket deserialize(QByteArray& ba);

QByteArray CComPacket::serialize()

    QByteArray ba;
    QDataStream ds(&ba, QIODevice::WriteOnly);

    ds << *this;
    return ba;


CComPacket CComPacket::deserialize(QByteArray& ba)

    QDataStream ds(&ba, QIODevice::ReadOnly);
    CComPacket cp;

    ds >> cp;
    return cp;

并且此测试代码现在可以正常工作(tmptmp2 相同):

CComPacket tmp;
tmp.m_cmd = CComPacket::Cmd::GiveName;
tmp.m_data = 5.112233;

QByteArray ba = tmp.serialize();
CComPacket tmp2 = CComPacket::deserialize(ba);

【讨论】:

以上是关于QVariant 反序列化给出无效值的主要内容,如果未能解决你的问题,请参考以下文章

没有从字符串值反序列化的字符串参数构造函数/工厂方法('2018-12-14')

根据字段值反序列化为密封子类

使用 Jackson 从 XML 到 POJO 的反序列化问题:没有从字符串值反序列化的字符串参数构造函数/工厂方法

反序列化错误 : 不能构造Dto的实例(尽管至少有一个Creator存在):不能从对象值反序列化。

Jackson MismatchedInputException(没有从字符串值反序列化的字符串参数构造函数/工厂方法)

将json键值反序列化为字典c#