簡體   English   中英

如何使用 YamlDotNet 將 YAML 解析為派生集合?

[英]How Can I Parse YAML Into a Derived Collection Using YamlDotNet?

使用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 ,確定我喜歡的類型,然后創建一個新JsonReaderJObject並重新解析的對象。

有沒有一種方法可以讀取、回滾,然后重新讀取nestedObjectDeserializer

是否有另一種對象類型可以調用nestedObjectDeserializer ,然后從中讀取Type屬性,最后繼續對派生類型進行正常的 YamlDotNet 解析?

這是不容易的。 這是一個 GitHub 問題,解釋了如何使用 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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM