【问题标题】:How Can I Parse YAML Into a Derived Collection Using YamlDotNet?如何使用 YamlDotNet 将 YAML 解析为派生集合?
【发布时间】:2017-03-21 22:00:20
【问题描述】:

使用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;
  }
}

我现在的问题是如何在调用nestedObjectDeserializer之前动态确定要选择的Type

使用 JSON.Net 时,我能够使用 CustomCreationConverter,将子 JSON 读入 JObject,确定我的类型,然后从 JObject 创建一个新的 JsonReader 并重新解析对象。

有没有办法让我阅读、回滚,然后重新阅读nestedObjectDeserializer

我可以在nestedObjectDeserializer 上调用另一种对象类型,然后从中读取Type 属性,最后通过派生类型的正常YamlDotNet 解析进行吗?

【问题讨论】:

    标签: c# parsing yamldotnet


    【解决方案1】:

    这并不容易。这是一个 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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-03
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-06
      相关资源
      最近更新 更多