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