2015-06-30 7 views
1

Я хочу десериализовать JSON-файл для объекта (класса) с помощью C++. Я посмотрел на библиотеку rapidjson, и каждый класс имел метод десериализации с параметром root как параметр, поэтому он может десериализоваться. Это выглядит так:JSON deserialization C++

void PoliceOfficer::Deserialize(rapidjson::Value& root) 
{ 
if (root.IsObject()) 
{ 
    if (root.HasMember("name")) 
    { 
     if (root["name"].IsString()) 
     { 
      name = root["name"].GetString(); 
     } 
    } 

    if (root.HasMember("maxHealth")) 
    { 
     if (root["maxHealth"].IsNumber()) 
     { 
      maxHealth = (float)root["maxHealth"].GetDouble(); 
     } 
    } 

    if (root.HasMember("skills")) 
    { 
     rapidjson::Value& skills = root["skills"]; 
     if (skills.IsArray()) 
     { 
      for (rapidjson::SizeType i = 0; i < skills.Size(); i++) 
      { 
       Skill tempSkill; 

       tempSkill.Deserialize(skills[i]); 

       m_skills.push_back(tempSkill); 
      } 
     } 
    } 
} 
} 

Но это похоже на большую работу. Вам придется реализовать этот метод во всех классах, которые вы хотите десериализовать сами. Так что мне было интересно, есть ли способ сделать это автоматически, что-то вроде следующей строки кода (Json.NET):

Movie m = JsonConvert.DeserializeObject<Movie>(json); 

, так что я не должен писать метод десериализации для всех классов. Я так делаю это единственный способ сделать это? Я использую quickjson, но я открыт для проверки другой библиотеки.

Я надеюсь, что этот вопрос имеет смысл :)

Спасибо заранее!

+0

C++ не имеет самоанализ, так что вы не можете напрямую сделать это, но вы можете посмотреть на [ boost hana] (http://ldionne.com/hana/index.html#tutorial-introspection-json). – Jarod42

+0

В принципе нет, извините –

+1

Я бы настоятельно предложил не строить его в ваш класс. Это делает ваши классы грязными и ваши кодовые спагетти. Вместо этого используйте бесплатные функции. Также ваш код очень многословный; рефакторируйте его так, чтобы это была всего одна строка для каждого члена, который вы читаете. –

ответ

1

Для решения такой проблемы, как у вас есть возможное решение, сконцентрируйте всю информацию в одной функции, где вы создаете поля структуры отображения < ---> записи в файле json/xml/ini. Что-то вроде этого:

struct abc_t 
{ 
    int a ; 
    string b ; 
} ; 

void serialize(serializer_t &serializer, abc_t &abc) 
{ 
    serializer.exx(abc.a, "abc") ; 
    serializer.exx(abc.b, "b") ; 
} 

Проблема заключается в том, как написать этот сериализатор. Решение может быть абстрактным классом, как это:

class serializer_t 
{ 
public: 
    virtual ~serializer_t(void) {} 
    virtual void exx(int &value, const char *tag) = 0 ; 
    virtual void exx(string &value, const char *tag) = 0 ; 
} ; 

тогда вы будете иметь два производных классов, serializer_writer_t, который реализует запись и serializer_reader_t реализующий чтение.

Другая возможность - это статический полиморфизм: это означает, что функция-шаблон void serialize(serializer_t &serializer, abc_t &abc). Если у вас есть составной объект, вам необходимо применить эту стратегию к каждому под-объекту.

Дайте взглянуть на boost.serialization вы найдете глубокое обсуждение всех компромиссных решений, участвующих в решении этой задачи

+0

Отличное решение, которое вы получили там! Благодаря! Но похоже, что нет решения, которое не требует значительного количества работы на C++. Поэтому я думаю, что я перейду на C# для этого случая, так как это намного проще и требует меньше кода. – user3071028

+0

@ user3071028 Если у вас есть эта степень свободы, тогда это лучший выбор. – marom