C# NewtonSoft.Json 使用 IEnumerable<ISomeInterface> 类型的属性序列化和反序列化类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11754633/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NewtonSoft.Json Serialize and Deserialize class with property of type IEnumerable<ISomeInterface>
提问by AndyDBell
I am trying to move some code to consume ASP.NET MVC Web API generated Json data instead of SOAP Xml.
我正在尝试移动一些代码来使用 ASP.NET MVC Web API 生成的 Json 数据而不是 SOAP Xml。
I have run into a problem with serializing and deserializing properties of type:
我遇到了序列化和反序列化类型属性的问题:
IEnumerable<ISomeInterface>.
Here is a simple example:
这是一个简单的例子:
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; }
}
}
I can serialize instances of SampleGroup easily with:
我可以轻松地序列化 SampleGroup 的实例:
var sz = JsonConvert.SerializeObject( sampleGroupInstance );
However the corresponding deserialize fails:
但是相应的反序列化失败:
JsonConvert.DeserializeObject<SampleGroup>( sz );
with this exception message:
带有此异常消息:
"Could not create an instance of type JsonSerializationExample.ISample. Type is an interface or abstract class and cannot be instantated."
“无法创建 JsonSerializationExample.ISample 类型的实例。类型是接口或抽象类,无法实例化。”
If I derive a JsonConverter I can decorate my property as follows:
如果我派生出一个 JsonConverter,我可以按如下方式装饰我的财产:
[JsonConverter( typeof (SamplesJsonConverter) )]
public IEnumerable<ISample> Samples { get; set; }
Here is the JsonConverter:
这是 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?
}
}
This converter solves the deserialization problem but I cannot figure how to code the WriteJson method to get serialization working again.
此转换器解决了反序列化问题,但我无法弄清楚如何编写 WriteJson 方法以使序列化再次工作。
Can anybody assist?
有人可以帮忙吗?
Is this a "correct" way to solve the problem in the first place?
这是首先解决问题的“正确”方法吗?
回答by fero
In my projects, this piece of code always worked as a default serializer which serializes the specified value as if there was no special converter:
在我的项目中,这段代码总是作为默认序列化器工作,它序列化指定的值,就好像没有特殊的转换器一样:
serializer.Serialize(writer, value);
回答by cuongle
You don't need to use JsonConverterAttribute, keep your model clean, also use CustomCreationConverter, the code is simpler:
你不需要使用JsonConverterAttribute,保持你的模型干净,也使用CustomCreationConverter,代码更简单:
public class SampleConverter : CustomCreationConverter<ISample>
{
public override ISample Create(Type objectType)
{
return new Sample();
}
}
Then:
然后:
var sz = JsonConvert.SerializeObject( sampleGroupInstance );
JsonConvert.DeserializeObject<SampleGroup>( sz, new SampleConverter());
Documentation: Deserialize with CustomCreationConverter
回答by dvr
I got this to work:
我得到了这个工作:
explicit conversion
显式转换
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;
}
回答by Daniel Melo
Great solution, thank you! I took the AndyDBell's question and Cuong Le's answer to build an example with two diferent interface's implementation:
很好的解决方案,谢谢!我根据 AndyDbell 的问题和 Cuong Le 的回答构建了一个具有两个不同接口实现的示例:
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();
}
}
And a generic version to the SampleConverter:
以及 SampleConverter 的通用版本:
public class SampleConverter<T> : CustomCreationConverter<ISample> where T: new ()
{
public override ISample Create(Type objectType)
{
return ((ISample)new T());
}
}
回答by Sunil S
It is quite simple and out of the box support provided by json.net, you just have to use the following JsonSettings while serializing and Deserializing:
它非常简单,并且由 json.net 提供开箱即用的支持,您只需在序列化和反序列化时使用以下 JsonSettings:
JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings()
{
TypeNameHandling =TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
});
and for Deserialzing use the below code:
对于反序列化,请使用以下代码:
JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects}
);
Just take a note of the JsonSerializerSettings object initializer, that is important for you.
只需记下 JsonSerializerSettings 对象初始值设定项,这对您很重要。
回答by Stanislav Trifan
Having that:
有那个:
public interface ITerm
{
string Name { get; }
}
public class Value : ITerm...
public class Variable : ITerm...
public class Query
{
public IList<ITerm> Terms { get; }
...
}
I managed conversion trick implementing that:
我管理转换技巧实现:
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;
}
}
It allows me to serialize and deserialize in JSON like:
它允许我在 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());
回答by adam.bielasty
I solved that problem by using a special setting for JsonSerializerSettingswhich is called TypeNameHandling.All
我通过对JsonSerializerSettings使用称为TypeNameHandling.All的特殊设置解决了该问题
TypeNameHandling setting includes type information when serializing JSON and read type information so that the create types are created when deserializing JSON
TypeNameHandling 设置包括序列化 JSON 时的类型信息和读取类型信息,以便在反序列化 JSON 时创建创建类型
Serialization:
序列化:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var text = JsonConvert.SerializeObject(configuration, settings);
Deserialization:
反序列化:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var configuration = JsonConvert.DeserializeObject<YourClass>(json, settings);
The class YourClassmight have any kind of base type fields and it will be serialized properly.
类YourClass可能有任何类型的基类型字段,并且它会被正确序列化。

