# #c# #json #firebase #deserialization #fire-sharp
Вопрос:
Приношу извинения за то, что задаю довольно распространенный вопрос, я искал повсюду и не могу найти решение, которое решило бы мою проблему.
Я использую Firesharp и пытаюсь десериализовать объект Json, который Firebase возвращает в класс с вложенным списком.
public class Class
{
public string Name { get; set; }
public string Desc { get; set; }
public string HPDie { get; set; }
public string Role { get; set; }
public int RPL { get; set; }
public IList<Level> Levels { get; set; }
public Class() { }
public Class(string name, string desc, string hpdie, string role, int rPL, List<Level> levels)
{
Name = name;
Desc = desc;
HPDie = hpdie;
RPL = rPL;
Levels = levels;
}
}
Как вы можете видеть, в нем есть список уровней, другой класс со следующим кодом:
public class Level
{
public int Number { get; set; }
public int BAB { get; set; }
public int FortSave { get; set; }
public int WillSave { get; set; }
public int RexSave { get; set; }
public int SpellsKnown { get; set; }
public List<Skill> Skills { get; set; }
public Level() { }
public Level(int number, int bab, int cmb, int cmd, int fortsave, int willsave, int rexsave, List<Skill> skills)
{
Number = number;
BAB = bab;
FortSave = fortsave;
WillSave = willsave;
RexSave = rexsave;
Skills = skills;
}
public class LevelList
{
List<Level> levellist { get; set; }
}
}
У этого в то же время есть список навыков. Класс навыков имеет только две строки: имя и описание.
Код, который я использую для десериализации, таков:
private async void RefreshClasses()
{
this.classList = new List<Class>();
FirebaseResponse res = await client.GetAsync("Class");
IEnumerable<Class> data = JsonConvert.DeserializeObject<IEnumerable<Class>>(res.Body);
if (data != null)
{
PopulateDGVClasses(data);
}
}
But when it gets to the Deserialization it returns the following error:
Ньютонсофт.Json.Исключение JsonSerializationException: «Не удается десериализовать текущий объект JSON (например, {«имя»:»значение»}) в систему типа».Коллекции.Общий.IEnumerable`1[CaminanteHelper.Class]’ потому что для правильного десериализации типа требуется массив JSON (например, [1,2,3]). Чтобы исправить эту ошибку, либо измените JSON на массив JSON (например, [1,2,3]), либо измените десериализованный тип, чтобы он был обычным .ЧИСТЫЙ тип (например, не примитивный тип, такой как целое число, не тип коллекции, такой как массив или список), который может быть десериализован из объекта JSON. Атрибут JsonObjectAttribute также можно добавить к типу, чтобы заставить его десериализоваться из объекта JSON. Путь «Варвар», строка 1, позиция 13.’
Опять же, я думаю, что смогу исправить это сам, но я застрял уже почти на два дня.
Заранее благодарю вас всех!
Редактировать: Json, который я пытаюсь десериализовать:
{
"Class" : {
"Barbarian" : {
"Desc" : "Barbarians excel in combat, possessing the martial prowess and fortitude to take on foes seemingly far superior to themselves. With rage granting them boldness and daring beyond that of most other warriors, barbarians charge furiously into battle and ruin all who would stand in their way.",
"HPDie" : "d12",
"Levels" : [ {
"BAB" : 2,
"FortSave" : 2,
"Number" : 1,
"RexSave" : 0,
"Skills" : {
"Prueba" : {
"Desc" : "Probota"
}
},
"SpellsKnown" : 0,
"WillSave" : 0
}, {
"BAB" : 3,
"FortSave" : 3,
"Number" : 2,
"RexSave" : 0,
"SpellsKnown" : 0,
"WillSave" : 0
}, {
"BAB" : 3,
"FortSave" : 3,
"Number" : 3,
"RexSave" : 1,
"SpellsKnown" : 0,
"WillSave" : 1
}, {
"BAB" : 4,
"FortSave" : 4,
"Number" : 4,
"RexSave" : 1,
"SpellsKnown" : 0,
"WillSave" : 1
}, {
"BAB" : 5,
"FortSave" : 4,
"Number" : 5,
"RexSave" : 1,
"SpellsKnown" : 0,
"WillSave" : 1
}, {
"BAB" : 6,
"FortSave" : 5,
"Number" : 6,
"RexSave" : 2,
"SpellsKnown" : 0,
"WillSave" : 2
}, {
"BAB" : 7,
"FortSave" : 5,
"Number" : 7,
"RexSave" : 2,
"SpellsKnown" : 0,
"WillSave" : 2
}, {
"BAB" : 8,
"FortSave" : 6,
"Number" : 8,
"RexSave" : 2,
"SpellsKnown" : 0,
"WillSave" : 2
}, {
"BAB" : 9,
"FortSave" : 6,
"Number" : 9,
"RexSave" : 3,
"SpellsKnown" : 0,
"WillSave" : 3
}, {
"BAB" : 10,
"FortSave" : 7,
"Number" : 10,
"RexSave" : 3,
"SpellsKnown" : 0,
"WillSave" : 3
} ],
"Name" : "Barbarian",
"RPL" : 4
},
"Wizard" : {
"Desc" : "While universalist wizards might study to prepare themselves for any manner of danger, specialist wizards research schools of magic that make them exceptionally skilled within a specific focus. rnrnYet no matter their specialty, all wizards are masters of the impossible and can aid their allies in overcoming any danger.",
"HPDie" : "d6",
"Levels" : [ {
"BAB" : 0,
"FortSave" : 0,
"Number" : 1,
"RexSave" : 0,
"SpellsKnown" : 4,
"WillSave" : 2
}, {
"BAB" : 1,
"FortSave" : 0,
"Number" : 2,
"RexSave" : 0,
"SpellsKnown" : 6,
"WillSave" : 3
}, {
"BAB" : 1,
"FortSave" : 1,
"Number" : 3,
"RexSave" : 1,
"SpellsKnown" : 7,
"WillSave" : 3
}, {
"BAB" : 2,
"FortSave" : 1,
"Number" : 4,
"RexSave" : 1,
"SpellsKnown" : 9,
"WillSave" : 4
}, {
"BAB" : 2,
"FortSave" : 1,
"Number" : 5,
"RexSave" : 1,
"SpellsKnown" : 10,
"WillSave" : 4
}, {
"BAB" : 3,
"FortSave" : 2,
"Number" : 6,
"RexSave" : 2,
"SpellsKnown" : 12,
"WillSave" : 5
}, {
"BAB" : 3,
"FortSave" : 2,
"Number" : 7,
"RexSave" : 2,
"SpellsKnown" : 14,
"WillSave" : 5
}, {
"BAB" : 4,
"FortSave" : 2,
"Number" : 8,
"RexSave" : 2,
"SpellsKnown" : 16,
"WillSave" : 6
}, {
"BAB" : 4,
"FortSave" : 3,
"Number" : 9,
"RexSave" : 3,
"SpellsKnown" : 18,
"WillSave" : 6
}, {
"BAB" : 5,
"FortSave" : 3,
"Number" : 10,
"RexSave" : 3,
"SpellsKnown" : 20,
"WillSave" : 7
} ],
"Name" : "Wizard",
"RPL" : 2
}
},
"Equipment" : {
"Battleaxe" : {
"ACBonus" : 0,
"ACType" : "(None)",
"Blunt" : false,
"Bonus" : "",
"Category" : "Weapon",
"Cost" : "10gp",
"DMG_Large" : "1d10",
"DMG_Medium" : "1d8",
"DMG_Small" : "1d6",
"Description" : "The handle of this axe is long enough that you can wield it one-handed or two-handed. The head may have one blade or two, with blade shapes ranging from half-moons to squared edges like narrower versions of woodcutting axes. The wooden haft may be protected and strengthened with metal bands called langets.",
"Name" : "Battleaxe",
"Penetrating" : false,
"Range" : "",
"Slashing" : true,
"Throwable" : false
},
"Composite Longbow" : {
"ACBonus" : 0,
"ACType" : "(None)",
"Blunt" : false,
"Bonus" : "If your STR is equal or more than the rating, add your STR bonus to damage made with this weapon.",
"Category" : "Weapon",
"Cost" : "100gp",
"DMG_Large" : "1d10",
"DMG_Medium" : "1d8",
"DMG_Small" : "1d6",
"Description" : "You need at least two hands to use a bow, regardless of its size. You can use a composite longbow while mounted.",
"Name" : "Composite Longbow",
"Penetrating" : true,
"Range" : "110ft",
"Slashing" : false,
"Throwable" : false
},
"Dagger" : {
"ACBonus" : 0,
"ACType" : "(None)",
"Blunt" : false,
"Bonus" : " 2 to Steal rolls made to hide this weapon.",
"Category" : "Weapon",
"Cost" : "6gp",
"DMG_Large" : "1d6",
"DMG_Medium" : "1d4",
"DMG_Small" : "1d3",
"Description" : "A one handed broad blade, shorter than a shortsword yet longer than a knife.",
"Name" : "Dagger",
"Penetrating" : true,
"Range" : "10ft",
"Slashing" : true,
"Throwable" : true
},
"Shield" : {
"ACBonus" : 2,
"ACType" : "Light",
"Blunt" : true,
"Bonus" : "",
"Category" : "Armor",
"Cost" : "12gp",
"DMG_Large" : "1d6",
"DMG_Medium" : "1d4",
"DMG_Small" : "1d2",
"Description" : "Made of leather.",
"Name" : "Shield",
"Penetrating" : false,
"Range" : "",
"Slashing" : false,
"Throwable" : false
},
"Sword" : {
"ACBonus" : 0,
"ACType" : "(None)",
"Blunt" : false,
"Bonus" : "",
"Category" : "Weapon",
"Cost" : "15gp",
"DMG_Large" : "1d10",
"DMG_Medium" : "1d8",
"DMG_Small" : "1d6",
"Description" : "This sword is about three and a half feet in length.",
"Name" : "Sword",
"Penetrating" : false,
"Range" : "",
"Slashing" : true,
"Throwable" : false
}
},
"Feat" : {
"Acrobatic" : {
"Desc" : " 2 to all of your Acrobatic rolls per each five character levels.",
"Name" : "Acrobatic",
"PreReq" : [ "" ],
"Type" : "General"
},
"Agile Maiden" : {
"Desc" : "For the purpose of class features (such as a ranger’s combat style, a barbarian’s fast movement, or a magus’s spellcasting), you treat Gray Maiden plate as medium armor or heavy armor, whichever is more beneficial to a given ability. This does not affect the armor’s statistics, and it is still considered heavy armor for all other purposes",
"Name" : "Agile Maiden",
"PreReq" : [ "Str 13", "Dex 13" ],
"Type" : "Combat"
}
},
"Spell" : {
"Cure Minor Wounds" : {
"CastingTime" : "None.",
"Desc" : "When laying your hand upon a living creature, you channel positive energy that cures 1d8 points of damage 1 point per caster level (maximum 5). Since undead are powered by negative energy, this spell deals damage to them instead of curing their wounds. An undead creature can apply Spell Resistance, and can attempt a Will save to take half damage.",
"Duration" : "Instantaneous.",
"FortRes" : false,
"Name" : "Cure Minor Wounds",
"PreReq" : [ "1 Divine" ],
"RexRes" : false,
"School" : "Conjuration",
"Target" : "Touched Creature.",
"WillRes" : true
},
"Magic Missile" : {
"CastingTime" : "None.",
"Desc" : "A missile of magical energy darts forth from your fingertip and strikes its target, dealing 1d4 1 points of force damage.rnrnThe missile strikes unerringly, even if the target is in melee combat, so long as it has less than total cover or total concealment. Specific parts of a creature can’t be singled out. Objects are not damaged by the spell.rnrnFor every two caster levels beyond 1st, you gain an additional missile – two at 3rd level, three at 5th, four at 7th, and the maximum of five missiles at 9th level or higher. If you shoot multiple missiles, you can have them strike a single creature or several creatures. A single missile can strike only one creature. You must designate targets before you check for spell resistance or roll damage.",
"Duration" : "Instantaneous.",
"FortRes" : false,
"Name" : "Magic Missile",
"PreReq" : [ "1 Divinern1 Arcanern1 Divinern1 Arcanern1 Divinern1 Arcanern" ],
"RexRes" : false,
"School" : "Evocation",
"Target" : "Up to five none of which can be separated by more than 15 ft.",
"WillRes" : false
}
}
}
Комментарии:
1. Это действительно поможет, если вы также добавите json, который пытаетесь десериализовать, поэтому все, что я говорю, основано на предположениях о необработанном json. Тем не менее, это похоже на распространенную ошибку. Вы просите его десериализовать
IEnumerable
(таким образом, массив json, начинающийся с[
и заканчивающийся,]
и вы, вероятно, предоставили ему один экземпляр (начиная с{
и заканчивая}
). Так что либо исправьте json (просто добавьте[]
все, что у вас есть сейчас), либо измените десериализацию на этуClass data = JsonConvert.DeserializeObject<Class>(res.Body);
.2. Приносим извинения, добавил Джсон. Оба решения предусматривали добавление [ ] для преобразования классов в массив, и, похоже, изменение кода не решило проблему.
3. Ваши структуры классов совершенно не подходят для json.
Class
не имеет имени, описания , hpdie и т. Д. Варвар и Волшебник делают это. Возможно, вы захотите использовать такой инструмент, как visual studio, чтобы вставить json в качестве классов, чтобы автоматически создавать свои классы, а затем изменять их по мере необходимости.4. Боюсь, я не понимаю, извините. Что я пытаюсь сделать, так это заполнить форму с подробной информацией о классе, а затем она загружается в Firebase, обновляя список внутри программы, где я могу выбрать имя класса, чтобы его данные заполнили форму, включили еще два списка уровней и навыков соответственно. Если я это сделаю, я не смогу добавлять новые классы, верно? Так как мне тоже нужно было бы создать новый класс внутри кода.
5. Во-первых, мой первоначальный комментарий был правильным, однако, поскольку есть еще проблемы, он все еще не работает после исправления (имейте в виду, что, хотя он устраняет описанную проблему, просто появляется новая проблема, я предполагаю, что вы получите немного другое сообщение об исключении). Как сказал @Crowcoder, ваши модели не соответствуют вашему json. В вашем json
Class
содержится 2 свойства:Barbarian
иWizard
. Эта структура не отражена в ваших моделях, поэтому она не может быть преобразована. Попробуйте такой инструмент, как json2csharp.com чтобы увидеть, как структурирован ваш json.
Ответ №1:
Это никоим образом не полный ответ. Я предполагаю, что вы не хотите сопоставлять/создавать классы для каждого «подкласса», например, Варвара, Волшебника и т. Д. Возможно, вы могли бы использовать JsonConverter. Пример обрабатывает только первый «анонимный» диапазон объектов. Может быть, вы найдете что-то из этого полезным.
var result = JsonConvert.DeserializeObject<Response>(jsonInput);
public class ClassJsonConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return new Class
{
ClassSpecifics = JObject.Load(reader).Values().Select(x => x.ToObject<ClassSpecifics>()).ToList()
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); }
}
public class Response
{
public Class Class { get; set; }
}
[JsonConverter(typeof(ClassJsonConverter))]
public class Class
{
public List<ClassSpecifics> ClassSpecifics { get; set; }
}
public class ClassSpecifics
{
public string Name { get; set; }
public string Desc { get; set; }
public string HPDie { get; set; }
public string Role { get; set; }
public int RPL { get; set; }
}
Комментарии:
1. Это сработало идеально, большое вам спасибо.