2014-07-09 239 views
17

我將通過說我知道問題是什麼,我只是不知道如何解決它。我正在與以JSON形式返回數據的.NET SOA數據層進行通信。一種這樣的方法返回一個對象,其中有多個集合。對象基本上是這樣的:類型是一個接口或抽象類,不能實例化

{ 
    "Name":"foo", 
    "widgetCollection":[{"name","foo"}, {"name","foo"},], 
    "cogCollection": [{"name","foo"}, {"childCogs",<<new collection>>},], 
} 

我的類,它表示這個對象是這樣的:

public class SuperWidget : IWidget 
{ 
    public string Name { get; set; } 

    public ICollection<IWidget> WidgetCollection { get; set; } 
    public ICollection<ICog> CogCollection { get; set; } 

    public SuperWidget() 
    { 
    } 

    [JsonConstructor] 
    public SuperWidget(IEnumerable<Widget> widgets, IEnumerable<Cog> cogs) 
    { 
     WidgetCollection = new Collection<IWidget>(); 
     CogCollection = new Collection<ICog>(); 

     foreach (var w in widgets) 
     { 
      WidgetCollection.Add(w); 
     } 
     foreach (var c in cogs) 
     { 
      CogCollection.Add(c); 
     } 
    } 
} 

直到cogCollection添加一個子集合這個構造函數工作得很好,現在我得到上述錯誤。一個具體的COG類看起來是這樣的:

[Serializable] 
public class Cog : ICog 
{ 
    public string name { get; set; } 

    public ICollection<ICog> childCogs { get; set; }   
} 

我不想因爲我使用的IoC到集合更改爲具體類型。因爲我正在使用IoC,所以我真的很想避免需要具有具體參數的JsonConstructors,但我還沒有想出一種方法來實現這一點。任何建議將不勝感激!

更新:

尤瓦Itzchakov的建議,這個問題可能是一個重複的是有點真(似乎)。在引用的帖子中,頁面中的一個答案提供了與此處提供的相同的解決方案。我沒有注意到答案,因爲OP的問題與我在這裏的問題不同。我的錯。

-------我的解決方案--------

正如我所說的:馬特的解決了工作的一點點,但我得到的東西設置爲我的作品。有一件事我不喜歡他的初步解決方案,是這樣的詩句:

return objectType == typeof(ICog); 

按照這個模式,你就需要有您收到過線每個抽象類型JsonConverter。這是低於我的情況理想,所以我創建了一個通用JsonConverter這樣:

public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T> 
{ 
    private readonly IUnityContainer Container; 
    public TalonJsonConverter(IUnityContainer container) 
    { 
     Container = container; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(T); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader); 
     var result = Container.Resolve<T>(); 
     serializer.Populate(target.CreateReader(), result); 
     return result; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 
} 

然後就在我反序列化我的數據,我做這樣的事情:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 
settings.Converters.Add((JsonConverter)Container.Resolve<IBaseJsonConverter<ICog>>()); 

普羅蒂普:如果您使用Resharper,(JsonConverter)會在這種情況下給你一個可疑的強制性警告。

希望別人認爲這有用!

+0

嘗試使用'JsonSerializerSettings'類的'TypeNameHandling.All'並將其傳遞給json串行器 –

+0

[JSON.NET中反串行化的接口接口]可能的重複(http://stackoverflow.com/questions/5780888/ cast-interfaces-for-deserialization-in-json-net) –

+0

[使用Json.NET轉換器反序列化屬性](http://stackoverflow.com/questions/2254872/using-json-net-converters-to -deserialize-properties) – nawfal

回答

22

您需要爲Json.Net提供一個自定義序列化程序來告訴它如何處理子輪齒。例如:

var settings = new JsonSerializerSettings(); 
settings.Converters.Add(new CogConverter()); 

CogConverter需要從JsonConverter繼承和指定它CanConvertICog接口。也許沿線的東西:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize(reader, typeof(Cog)); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 
} 

我建議您註冊您的JsonSerializerSettings與您的IoC容器在這種情況下。如果序列化程序不能負責實際構建Cog本身,您也可以考慮授予對容器的訪問權限CogConverter;這一切都取決於你的特定架構。

編輯

經過進一步的閱讀,它好像你可能會尋找具體如何使用IoC的人口創造了ICog。我用以下爲我ReadJson的一部分:你希望你的DetermineConcreteType方法內部

var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader); 
var objectType = DetermineConcreteType(target); 
var result = iocContainer.Resolve(objectType); 
serializer.Populate(target.CreateReader(), result); 
return result; 

這允許你使用任何對象,從原來的JSON填充它,使用自定義類型。

+1

謝謝,馬特。我會稍微說一下,看看它是否有效。 – dparsons

+0

隨着一點點工作,這是正確的答案。我很好奇,你的'DetermineConcreteType'方法是做什麼的? – dparsons

+0

在我們的系統中,我們看一下它的一些屬性來確定一個正確的子類型(我們的接口與實現不是1:1) - 我能想到的一個通用的屬性是一個下拉表示付款方式(信用卡vs銀行等) - 每個都有不同的字段,但下拉的值可以指示該類型。如果你有你想要共享的代碼作爲答案的一部分,我很樂意更新我的代碼以包含更完整的解決方案。 –

相關問題