2012-08-01 39 views
51

我試圖移動一些代碼來使用ASP.NET MVC Web API生成的Json數據而不是SOAP Xml。NewtonSoft.Json具有IEnumerable <ISomeInterface>類型屬性的序列化和反序列化類

我已經運行與序列化和反序列化類型的屬性的問題:

IEnumerable<ISomeInterface>. 

下面是一個簡單的例子:

public interface ISample{ 
    int SampleId { get; set; } 
} 
public class Sample : ISample{ 
    public int SampleId { get; set; } 
} 
public class SampleGroup{ 
    public int GroupId { get; set; } 
    public IEnumerable<ISample> Samples { get; set; } 
} 
} 

我可以容易序列SampleGroup的實例

var sz = JsonConvert.SerializeObject(sampleGroupInstance); 

但是相應的反序列化失敗:

JsonConvert.DeserializeObject<SampleGroup>(sz); 

與此異常的消息:

「無法創建類型JsonSerializationExample.ISample的一個實例。類型是一個接口或抽象類,不能instantated「

如果我得到一個JsonConverter我可以裝點我的財產如下:

[JsonConverter(typeof (SamplesJsonConverter))] 
public IEnumerable<ISample> Samples { get; set; } 

這裏是JsonConverter:

public class SamplesJsonConverter : JsonConverter{ 
    public override bool CanConvert(Type objectType){ 
    return (objectType == typeof (IEnumerable<ISample>)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){ 
    var jA = JArray.Load(reader); 
    return jA.Select(jl => serializer.Deserialize<Sample>(new JTokenReader(jl))).Cast<ISample>().ToList(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer){ 
    ... What works here? 
    } 
} 

這轉換器解決了反序列化問題,但我不知道如何編寫WriteJson方法來重新獲得序列化。

任何人都可以協助嗎?

這是解決問題的「正確」方法嗎?

+0

除了下面的答案,您可以覆蓋['CanWrite'](http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonConverter_CanWrite.htm)並返回'false'。請參閱[如何在自定義JsonConverter中使用默認序列化](https://stackoverflow.com/questions/29616596/how-to-use-default-serialization-in-a-custom-jsonconverter/29616648#29616648)。 – dbc 2017-02-04 20:40:54

回答

2

在我的項目,這段代碼始終擔任該序列化指定值的默認的序列,好像沒有特別的轉換器:

serializer.Serialize(writer, value); 
+2

序列化工作正常。問題是反序列化爲聲明爲接口的屬性。實現一個CustomCreationConverter並將其傳遞給JsonConvert.DeserializeObject似乎是答案。 – AndyDBell 2012-08-01 22:00:36

58

你並不需要使用JsonConverterAttribute,保持你的模型乾淨,還用CustomCreationConverter,代碼簡單:

public class SampleConverter : CustomCreationConverter<ISample> 
{ 
    public override ISample Create(Type objectType) 
    { 
     return new Sample(); 
    } 
} 

然後:

var sz = JsonConvert.SerializeObject(sampleGroupInstance); 
JsonConvert.DeserializeObject<SampleGroup>(sz, new SampleConverter()); 

文檔:Deserialize with CustomCreationConverter

+1

謝謝。這很好。 – AndyDBell 2012-08-01 22:01:34

+1

謝謝,你救了我的一天。我自己的JsonConverter沒有工作我不知道爲什麼。你的解決方案就像一個魅力,而且更簡單 – 2016-09-01 10:56:33

1

我得到這個工作:

顯式轉換

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 
            JsonSerializer serializer) 
    { 
     var jsonObj = serializer.Deserialize<List<SomeObject>>(reader); 
     var conversion = jsonObj.ConvertAll((x) => x as ISomeObject); 

     return conversion; 
    } 
4

的最佳解決方案,謝謝! 我把AndyDBell的問題的Cuong樂的答案建有兩個diferent接口的實現的例子:

public interface ISample 
{ 
    int SampleId { get; set; } 
} 

public class Sample1 : ISample 
{ 
    public int SampleId { get; set; } 
    public Sample1() { } 
} 


public class Sample2 : ISample 
{ 
    public int SampleId { get; set; } 
    public String SampleName { get; set; } 
    public Sample2() { } 
} 

public class SampleGroup 
{ 
    public int GroupId { get; set; } 
    public IEnumerable<ISample> Samples { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     //Sample1 instance 
     var sz = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1},{\"SampleId\":2}]}"; 
     var j = JsonConvert.DeserializeObject<SampleGroup>(sz, new SampleConverter<Sample1>()); 
     foreach (var item in j.Samples) 
     { 
      Console.WriteLine("id:{0}", item.SampleId); 
     } 
     //Sample2 instance 
     var sz2 = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1, \"SampleName\":\"Test1\"},{\"SampleId\":2, \"SampleName\":\"Test2\"}]}"; 
     var j2 = JsonConvert.DeserializeObject<SampleGroup>(sz2, new SampleConverter<Sample2>()); 
     //Print to show that the unboxing to Sample2 preserved the SampleName's values 
     foreach (var item in j2.Samples) 
     { 
      Console.WriteLine("id:{0} name:{1}", item.SampleId, (item as Sample2).SampleName); 
     } 
     Console.ReadKey(); 
    } 
} 

和通用版本的SampleConverter:

public class SampleConverter<T> : CustomCreationConverter<ISample> where T: new() 
{ 
    public override ISample Create(Type objectType) 
    { 
     return ((ISample)new T()); 
    } 
} 
15

這是相當簡單了由json.net提供的box支持,您只需在序列化和反序列化時使用以下JsonSettings:

JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings() 
{ 
    TypeNameHandling =TypeNameHandling.Objects, 
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple 
}); 

and for De序列化使用以下代碼:

JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type, 
    new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects} 
); 

只需記下JsonSerializerSettings對象初始值設定項,這對您很重要。

0

有了這樣的:

public interface ITerm 
{ 
    string Name { get; } 
} 

public class Value : ITerm... 

public class Variable : ITerm... 

public class Query 
{ 
    public IList<ITerm> Terms { get; } 
... 
} 

我管理轉換技巧實現的是:

public class TermConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var field = value.GetType().Name; 
     writer.WriteStartObject(); 
     writer.WritePropertyName(field); 
     writer.WriteValue((value as ITerm)?.Name); 
     writer.WriteEndObject(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 
     JsonSerializer serializer) 
    { 
     var jsonObject = JObject.Load(reader); 
     var properties = jsonObject.Properties().ToList(); 
     var value = (string) properties[0].Value; 
     return properties[0].Name.Equals("Value") ? (ITerm) new Value(value) : new Variable(value); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof (ITerm) == objectType || typeof (Value) == objectType || typeof (Variable) == objectType; 
    } 
} 

它讓我序列化和JSON反序列化,如:

string JsonQuery = "{\"Terms\":[{\"Value\":\"This is \"},{\"Variable\":\"X\"},{\"Value\":\"!\"}]}"; 
... 
var query = new Query(new Value("This is "), new Variable("X"), new Value("!")); 
var serializeObject = JsonConvert.SerializeObject(query, new TermConverter()); 
Assert.AreEqual(JsonQuery, serializeObject); 
... 
var queryDeserialized = JsonConvert.DeserializeObject<Query>(JsonQuery, new TermConverter()); 
7

我解決了這個問題通過使用特殊設置JsonSerializerSettings這被稱爲TypeNameHandling.All

TypeNameHandling設置包括類型信息序列化JSON時,並且使得反序列化JSON

序列化時創建的創建類型讀類型信息:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 
var text = JsonConvert.SerializeObject(configuration, settings); 

反序列化:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 
var configuration = JsonConvert.DeserializeObject<YourClass>(json, settings); 

YourClass可能有什麼樣的基本類型字段,它會被正確序列化。

相關問題