使用YamlDotNet,我试图反序列化以下YAML:
Collection:
- Type: TypeA
TypeAProperty: value1
- Type: TypeB
TypeBProperty: value2
Type
属性是Collection
下所有对象的必需属性。其余属性取决于类型。
这是我理想的对象模型:
public class Document
{
public IEnumerable<IBaseObject> Collection { get; set; }
}
public interface IBaseObject
{
public string Type { get; }
}
public class TypeAClass : IBaseObject
{
public string Type { get; set; }
public string TypeAProperty { get; set; }
}
public class TypeBClass : IBaseObject
{
public string Type { get; set; }
public string TypeBProperty { get; set; }
}
根据我的阅读,我认为最好的办法是使用从INodeDeserializer
派生的自定义节点反序列化器。作为概念证明,我可以这样做:
public class MyDeserializer : INodeDeserializer
{
public bool Deserialize(IParser parser, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
{
if (expectedType == typeof(IBaseObject))
{
Type type = typeof(TypeAClass);
value = nestedObjectDeserializer(parser, type);
return true;
}
value = null;
return false;
}
}
我现在的问题是如何在致电Type
之前动态确定要选择的nestedObjectDeserializer
。
使用JSON.Net时,我能够使用CustomCreationConverter
,将子JSON读入JObject
,确定我的类型,然后从{创建一个新的JsonReader
{1}}并重新解析对象。
有没有办法可以阅读,回滚,然后重新阅读JObject
?
我可以在nestedObjectDeserializer
上调用另一个对象类型,然后从那里读取nestedObjectDeserializer
属性,最后通过正常的YamlDotNet解析派生类型吗?
答案 0 :(得分:0)
这不容易。这是一个GitHub issue,说明了如何使用YamlDotNet进行多态序列化。
您的情况下,一个简单的解决方案是两步反序列化。首先,您将序列化为某种中间形式,然后将其转换为模型。由于您可以限制YamlDotNet内部的挖掘,因此相对容易:
public class Step1Document
{
public List<Step1Element> Collection { get; set; }
public Document Upcast()
{
return new Document
{
Collection = Collection.Select(m => m.Upcast()).ToList()
};
}
}
public class Step1Element
{
// Fields from TypeA and TypeB
public string Type { get; set; }
public string TypeAProperty { get; set; }
public string TypeBProperty { get; set; }
internal IBaseObject Upcast()
{
if(Type == "TypeA")
{
return new TypeAClass
{
Type = Type,
TypeAProperty = TypeAProperty
};
}
if (Type == "TypeB")
{
return new TypeBClass
{
Type = Type,
TypeBProperty = TypeBProperty
};
}
throw new NotImplementedException(Type);
}
}
要反序列化:
var serializer = new DeserializerBuilder().Build();
var document = serializer.Deserialize<Step1Document>(data).Upcast();