2017-09-05 326 views
0

我需要爲現有報告界面實現遠程連接,這需要序列化和反序列化數據類。這裏是類和接口的簡化版本:JSON Newtonsoft C#反序列化不同類型的對象列表

public interface IBase 
    { 
     string Name { get; } 
    } 

    public interface IDerived1 
    { 
     int Value { get; } 
    } 

    public interface IDerived2 
    { 
     bool Value { get; } 
    } 

    public class Base : IBase 
    { 
     public string Name { get; protected set; } 
    } 

    public class Derived1 : Base, IDerived1 
    { 
     public int Value { get; protected set; } 
    } 

    public class Derived2 : Base, IDerived2 
    { 
     public bool Value { get; protected set; } 
    } 

作爲輸入參數,我得到

IEnumerable<IBase> reportingData 

所以這個集合可能包含「Derived1」和「Derived2的」實例的任何數量和組合。然後我連載這樣的集合:

string serialisedReportingData = JsonConvert.SerializeObject(reportingData); 

這使我如此:

[{ 「值」:11, 「姓名」: 「產品編號」},{ 「值」:假的,「Name」:「Output 1 Enabled」}]

很顯然,單獨使用這些數據,反序列化是不可能的,因爲單個集合條目的類型不在JSON中。例如,我可以將類型部分作爲JSON的一部分,或者提供額外的類型集合以便在反序列化過程中使用。

我用CustomCreationConverter過載前應對

JsonConvert.DeserializeObject<IEnumerable<Ixxx>>(...); 

類型的場景,但這僅適用於IEnumerable的內一個單一的接口類型。在我上面的例子中,我有兩個:IDerived1和IDerived2。

我的問題/問題:

一)我不知道如何CustomCreationConverter可以寫,與一個以上的接口類型交易和我不知道怎麼弄的類型到這個。

b)我很樂意提供關於如何實現解決方案的建議,該解決方案可以爲我提供與收到的'IEnumerable reportingData'相同的反序列化輸出。

如果可能,我會非常感謝一個有效的代碼示例。

提前許多感謝, 基督教

+0

如果你不想包含'「$型」'信息,請參見如何實現自定義JsonConverter在JSON.NET反序列化基類對象的列表?(https://開頭計算器。com/q/8030538)和[使用json.net反序列化多態json類而沒有類型信息](https://stackoverflow.com/q/19307752)。 – dbc

回答

1

更新:(由DBC評論啓發)

與類型名反序列化時,應使用一個SerializationBinder。 請參閱KnownTypesBinder。 (需要Newtonsoft.Json版本大於10)

首先,如果你想設置你的屬性,你必須讓它們爲public。 然後,您可以使用JsonSerializerSettings來序列化/反序列化。

List<IBase> loList = new List<IBase>(); 
loList.Add(new Base() { Name = "Base" }); 
loList.Add(new Derived1() { Name = "Derived1", Value = 3 }); 
loList.Add(new Derived2() { Name = "Derived2", Value = true }); 

KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder() 
{ 
    KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) } 
}; 

IEnumerable<IBase> reportingData = loList.AsEnumerable(); 
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings() 
{ 
    TypeNameHandling = TypeNameHandling.Objects, 
    SerializationBinder = loKnownTypesBinder 
}; 

string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings); 
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings); 

如果使用類似JsonSerializerSettings的類型信息將被包含在json字符串中。

[{ 
     "$type": "Base", 
     "Name": "Base" 
    }, { 
     "$type": "Derived1", 
     "Value": 3, 
     "Name": "Derived1" 
    }, { 
     "$type": "Derived2", 
     "Value": true, 
     "Name": "Derived2" 
    } 
] 
+0

爲了安全起見,應對$ type信息進行消毒。有關詳細信息,請參見[Newtonsoft Json中的[TypeNameHandling注意事項](https://stackoverflow.com/q/39565954)。 – dbc

+0

@dbc:Thx。我已經更新了我的答案。 – PinBack

+0

謝謝SOOOO!我沒有想到答案是那麼簡單。不僅我,而且我的一些同事會非常感謝你的智慧! :-) – Christian