Как десериализовать YAML с полем без имени?
Есть такой YAML
681:
activities:
copying:
time: 480
manufacturing:
materials:
- quantity: 86
typeID: 38
products:
- quantity: 1
typeID: 165
time: 600
research_material:
time: 210
research_time:
time: 210
blueprintTypeID: 681
maxProductionLimit: 300
682:
activities:
copying:
time: 480
manufacturing:
materials:
- quantity: 133
typeID: 38
products:
- quantity: 1
typeID: 166
time: 600
research_material:
time: 210
research_time:
time: 210
blueprintTypeID: 682
maxProductionLimit: 300
Есть такие модели
public class Root
{
public List<bl> bl { get; set; }
}
public class bl
{
public activities activities { get; set; }
}
public class activities
{
public copying copying { get; set; }
public manufacturing manufacturing { get; set; }
public research_material research_Material { get; set; }
public research_time research_time { get; set; }
public int blueprintTypeID { get; set; }
public int maxProductionLimit { get; set; }
}
public class copying
{
public int time { get; set; }
}
public class manufacturing
{
public int time { get; set; }
public materials materials { get; set; }
public products products { get; set; }
}
public class materials
{
public int quantity { get; set; }
public int typeID { get; set; }
}
public class products
{
public int quantity { get; set; }
public int typeID { get; set; }
}
public class research_material
{
public int time { get; set; }
}
public class research_time
{
public int time { get; set; }
}
}
Я использую YamlDotNet. Пытаюсь десериализовать
string path = @"bl.yaml";
string yaml;
using (StreamReader reader = new StreamReader(path))
{
yaml = await reader.ReadToEndAsync();
}
var deserializer = new DeserializerBuilder().Build();
var p = deserializer.Deserialize<Root>(yaml);
Получаю ошибку YamlDotNet.Core.YamlException: "Property '681' not found on type 'evesell.Root'." Пишет что я не добавил в модель поле для свойства '681'. Но как мне его добавить если у него нет имени?
Ответы (1 шт):
Корнем этих данных является словарь. Поэтому в C# нужно использовать тип Dictionary<,>.
Заодно давайте исправим нейминг на общепринятый.
Пространства имён:
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
Классы-модели:
public class Data
{
public Activities Activities { get; set; }
[YamlMember(Alias = "blueprintTypeID", ApplyNamingConventions = false)]
public int BlueprintTypeId { get; set; }
public int MaxProductionLimit { get; set; }
}
public class Activities
{
public Copying Copying { get; set; }
public Manufacturing Manufacturing { get; set; }
[YamlMember(Alias = "research_material", ApplyNamingConventions = false)]
public ResearchMaterial ResearchMaterial { get; set; }
[YamlMember(Alias = "research_time", ApplyNamingConventions = false)]
public ResearchTime ResearchTime { get; set; }
}
public class Copying
{
public int Time { get; set; }
}
public class Manufacturing
{
public int Time { get; set; }
public Material[] Materials { get; set; }
public Product[] Products { get; set; }
}
public class Material
{
public int Quantity { get; set; }
[YamlMember(Alias = "typeID", ApplyNamingConventions = false)]
public int TypeId { get; set; }
}
public class Product
{
public int Quantity { get; set; }
[YamlMember(Alias = "typeID", ApplyNamingConventions = false)]
public int TypeId { get; set; }
}
public class ResearchMaterial
{
public int Time { get; set; }
}
public class ResearchTime
{
public int Time { get; set; }
}
Bl - странное название для класса, я его назвал Data. Но это неважно.
Все свойства в C# именуются в стиле PascalCase - с большой буквы.
Поля в показанном yaml имеют стиль camelCase - с маленькой буквы.
Поэтому задаём правило именования CamelCaseNamingConvention.
Часть полей в yaml имеют знаки подчёркивания в названии: стиль snake_case или UnderscoredNamingConvention. Насколько я понял, совместить два стиля одновременно нет возможности. Поэтому на такие свойства пришлось навесить атрибуты YamlMember с указанием алиаса имени.
А также этот атрибут добавляем на свойства с суффиксом Id - в C# в соответствии с Framework Design Guidelinges он пишется именно так, а в yaml задано ID.
Названия классов Material и Product - в единственном числе. А вот названия свойств - во множественном: Materials, Products, т. к. это коллекции. Вместо массивов можно использовать любой другой подходящий тип коллекции, например, List<>.
Часть классов имеют одинаковый набор свойств. Возможно, следует сделать всего один общий класс. Но это вам виднее.
В итоге код десериализации с добавлением конвенции выглядит так:
string yaml = await File.ReadAllTextAsync(path);
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.Build();
var dictionary = deserializer.Deserialize<Dictionary<int, Data>>(yaml);