2017-10-12 88 views
2

我有一個通用類型Container<IContentType>其中接口IContentType可以是四個具體ContentX類型之一。反序列化一個通用類型

我序列化,一切都很好。

當使用Newtonsoft反序列化時,我使用自定義類型轉換器和var model = JsonConvert.DeserializeObject<Container<ContentA>>(json, settings)工程。調試器顯示我有一個Container<ContentA>對象。

我的計劃是反序列化以嘗試對四種可能的ContentX類型中的每一種進行反序列化,並在默認情況下捕獲一個異常,直到我「猜出」正確的異常。

但是,如果我這樣做的方法中,像這樣:

public static Container<IContentType> Deserialize(jsonfile) 
{ 
    ... 
    var model = JsonConvert.DeserializeObject<Container<ContentA>>(json, settings) 
    return model; 
} 

我得到「無法隱式轉換Container<ContentA>Container<IContentType>」。 ContentA器具IContentType

有沒有一種方法可以創建一個演員操作,轉換,動態或使隱式轉換工作?

+0

爲什麼不只是'JsonConvert.DeserializeObject >(json,settings)作爲Container '? –

+0

您已遇到差異問題。例如,即使'string'是'object'的子類,你不能將'List '強制轉換爲'List ',因爲那麼'List '引用將會有一個方法'Add(Object)',這對於引用「指向」的實際「列表」不適用。 –

+2

您將需要爲'IContentType'創建一個自定義的'JsonConverter',並按照[如何在JSON.NET中實現自定義JsonConverter來反序列化基類對象的列表]這兩行來推斷正確的具體類型?](https:// stackoverflow.com/q/8030538/3744182)或[使用json.net反序列化沒有類型信息的多態json類](https://stackoverflow.com/q/19307752/3744182)或[Json.Net帶多形子類型的序列化對象(https://stackoverflow.com/q/29528648/3744182)。然後你可以反序列化到'Container '。 – dbc

回答

2

而不是試圖反序列化作爲Container<ContentX>混凝土類型X,應作爲一個Container<IContentType>使用custom JsonConverter該JSON預加載到JToken並推斷沿着How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?Deserializing polymorphic json classes without type information using json.net線具體類型反序列化或Json.Net Serialization of Type with Polymorphic Child Object

因此,你的轉換器看起來是這樣的:

public class ContentConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(IContentType); 
    } 

    Type GetConcreteType(JObject obj) 
    { 
     if (obj.GetValue(nameof(ContentA.SomePropertyOfContentA), StringComparison.OrdinalIgnoreCase) != null) 
      return typeof(ContentA); 
     // Add other tests for other content types. 
     // Return a default type or throw an exception if a unique type cannot be found. 
     throw new JsonSerializationException("Cannot determine concrete type for IContentType"); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var obj = JObject.Load(reader); 
     var concreteType = GetConcreteType(obj); 
     return obj.ToObject(concreteType, serializer); 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

而且您的來電JsonConvert會是什麼樣子:

var settings = new JsonSerializerSettings 
{ 
    Converters = { new ContentConverter() }, 
}; 
var model = JsonConvert.DeserializeObject<Container<IContentType>>(json, settings); 

最後,你也許能夠使用的選型完全自動

new JsonDerivedTypeConverer<IContentType>(typeof(ContentA), typeof(ContentB), typeof(ContentC), typeof(ContentD)) 

其中JsonDerivedTypeConverer<T>取自JsonConverter with Interface