NewtonSoft.Json使用IEnumerable <ISomeInterface>types的属性对类进行序列化和反序列化

我试图移动一些代码来消费ASP.NET MVC Web API生成的Json数据,而不是SOAP Xml。

我遇到了序列化和反序列化types属性的问题:

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 ); 

有这个例外的消息:

“无法创buildJsonSerializationExample.ISampletypes的实例,Type是一个接口或抽象类,不能被瞬时化。

如果我派生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方法来获得序列化的工作。

有人可以协助吗?

这是否是解决问题的“正确”方法?

你不需要使用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()); 

文档: 使用CustomCreationConverter进行反序列化

这是相当简单和开箱即用的json.net提供的支持,你只需要在序列化和反序列化时使用下面的JsonSettings:

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

和反序列化使用下面的代码:

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

只需记下JsonSerializerSettings对象初始值设定项,这对您很重要。

我通过为JsonSerializerSettings使用了一个名为TypeNameHandling.All的特殊设置来解决这个问题

TypeNameHandling设置包括序列化JSON时的types信息和读取types信息,以便在反序列化JSON时创build创buildtypes

连载:

 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类可能有任何types的基types字段,它将被正确序列化。

伟大的解决scheme,谢谢! 我采取了AndyDBell的问题和Cuong Le的答案来构build一个具有两个不同接口的实现的例子:

 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()); } } 

在我的项目中,这段代码总是作为一个默认的序列化器,将指定的值序列化,就好像没有特殊的转换器一样:

 serializer.Serialize(writer, value); 

我得到这个工作:

明确的转换

  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; } 

有这样的:

 public interface ITerm { string Name { get; } } public class Value : ITerm... public class Variable : ITerm... public class Query { public IList<ITerm> Terms { get; } ... } 

我pipe理转换技巧实现:

 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());