JSON.NET – 如何反序列化接口实例的集合?

我想通过json.net序列化这段代码:

public interface ITestInterface { string Guid {get;set;} } public class TestClassThatImplementsTestInterface1 { public string Guid { get;set; } } public class TestClassThatImplementsTestInterface2 { public string Guid { get;set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List<ITestInterface>(); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); } List<ITestInterface> CollectionToSerialize { get;set; } } 

我想用json.net序列化/反序列化ClassToSerializeViaJson。 序列化正在工作,但反序列化给了我这个错误:

Newtonsoft.Json.JsonSerializationException:无法创buildITestInterfacetypes的实例。 Type是一个接口或抽象类,不能被实例化。

那么如何反序列化List集合?

谢谢

贝娄全面工作的例子,你想做什么:

 public interface ITestInterface { string Guid { get; set; } } public class TestClassThatImplementsTestInterface1 : ITestInterface { public string Guid { get; set; } public string Something1 { get; set; } } public class TestClassThatImplementsTestInterface2 : ITestInterface { public string Guid { get; set; } public string Something2 { get; set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List<ITestInterface>(); } public List<ITestInterface> CollectionToSerialize { get; set; } } public class TypeNameSerializationBinder : SerializationBinder { public string TypeFormat { get; private set; } public TypeNameSerializationBinder(string typeFormat) { TypeFormat = typeFormat; } public override void BindToName(Type serializedType, out string assemblyName, out string typeName) { assemblyName = null; typeName = serializedType.Name; } public override Type BindToType(string assemblyName, string typeName) { var resolvedTypeName = string.Format(TypeFormat, typeName); return Type.GetType(resolvedTypeName, true); } } class Program { static void Main() { var binder = new TypeNameSerializationBinder("ConsoleApplication.{0}, ConsoleApplication"); var toserialize = new ClassToSerializeViaJson(); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface1() { Guid = Guid.NewGuid().ToString(), Something1 = "Some1" }); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface2() { Guid = Guid.NewGuid().ToString(), Something2 = "Some2" }); string json = JsonConvert.SerializeObject(toserialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); var obj = JsonConvert.DeserializeObject<ClassToSerializeViaJson>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); Console.ReadLine(); } } 

我在尝试自己做这件事时发现了这个问题。 在我实施加拉斯的回答之后 ,我感到似乎有多么简单。 如果我只是实现一个已经被传递的方法,我想实例化的确切types(作为一个string),为什么不是库自动绑定它?

实际上,我发现我不需要任何定制的粘合剂,Json.Net能够做到我所需要的,只要我告诉它,那就是我正在做的。

序列化时:

 string serializedJson = JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple }); 

反序列化时:

 var deserializedObject = JsonConvert.DeserializeObject<ClassToSerializeViaJson>(serializedJson, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }); 

相关文档: Json.NET的序列化设置TypeNameHandling设置

我也对Garath的简单性感到惊讶,也得出了Json库可以自动完成的结论。 但我也认为它比Ben Jenkinson的答案更简单(尽pipe我可以看到json库本身的开发者已经修改了它)。 从我的testing中,你所需要做的就是将TypeNameHandling设置为Auto,如下所示:

 var objectToSerialize = new List<IFoo>(); // TODO: Add objects to list var jsonString = JsonConvert.SerializeObject(objectToSerialize, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); var deserializedObject = JsonConvert.DeserializeObject<List<IFoo>>(jsonString, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); 

使用默认设置,你不能。 JSON.NET没有办法知道如何反序列化数组。 但是,您可以指定将哪种types的转换器用于您的接口types。 要了解如何执行此操作,请参阅此页面: http : //blog.greatrexpectations.com/2012/08/30/deserializing-interface-properties-using-json-net/

您也可以在这个SO问题中find有关此问题的信息: 在JSON.NET中为反序列化投射接口

Inrego的答案近似重复,但值得进一步解释:

如果您使用TypeNameHandling.Auto那么只需要包含types/程序集的名称(即接口和基类/派生类)。 所以你的JSON更清晰,更小,更具体。

这不是XML / SOAP的主要卖点之一吗?

这是一个古老的问题,但认为我会添加一个更深入的答案(以我写的文章的forms): http : //skrift.io/articles/archive/bulletproof-interface-deserialization-in-jsonnet /

TLDR:与其configurationJson.NET在序列化的JSON中embeddedtypes名称,您可以使用JSON转换器来确定要使用您喜欢的任何自定义逻辑反序列化哪个类。

这有一个好处,你可以重构你的types而不用担心反序列化的破坏。

我想反序列化我的应用程序没有序列化的JSON,因此我需要手动指定具体的实现。 我已经扩大了尼古拉斯的答案。

可以说我们有

 public class Person { public ILocation Location { get;set; } } 

和具体的例子

 public class Location: ILocation { public string Address1 { get; set; } // etc } 

添加在这个类中

 public class ConfigConverter<I, T> : JsonConverter { public override bool CanWrite => false; public override bool CanRead => true; public override bool CanConvert(Type objectType) { return objectType == typeof(I); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new InvalidOperationException("Use default serialization."); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var deserialized = (T)Activator.CreateInstance(typeof(T)); serializer.Populate(jsonObject.CreateReader(), deserialized); return deserialized; } } 

然后用JsonConverter属性定义你的接口

 public class Person { [JsonConverter(typeof(ConfigConverter<ILocation, Location>))] public ILocation Location { get;set; } }