NewtonSoft.Json使用IEnumerable类型的属性序列化和反序列化类<ISomeInterface>

And*_*ell 63 c# serialization json json.net deserialization

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

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

IEnumerable<ISomeInterface>.
Run Code Online (Sandbox Code Playgroud)

这是一个简单的例子:

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; }
 }
}
Run Code Online (Sandbox Code Playgroud)

我可以使用以下命令轻松序列化SampleGroup的实例:

var sz = JsonConvert.SerializeObject( sampleGroupInstance );
Run Code Online (Sandbox Code Playgroud)

但是相应的反序列化失败:

JsonConvert.DeserializeObject<SampleGroup>( sz );
Run Code Online (Sandbox Code Playgroud)

使用此异常消息:

"无法创建JsonSerializationExample.ISample类型的实例.Type是接口或抽象类,无法立即显示."

如果我派生出一个JsonConverter,我可以按如下方式装饰我的属性:

[JsonConverter( typeof (SamplesJsonConverter) )]
public IEnumerable<ISample> Samples { get; set; }
Run Code Online (Sandbox Code Playgroud)

这是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?
  }
}
Run Code Online (Sandbox Code Playgroud)

这个转换器解决了反序列化问题,但我无法想象如何编写WriteJson方法以使序列化再次工作.

有人可以帮忙吗?

这首先是解决问题的"正确"方法吗?

cuo*_*gle 66

你不需要使用JsonConverterAttribute,保持你的模型干净,也使用CustomCreationConverter,代码更简单:

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

然后:

var sz = JsonConvert.SerializeObject( sampleGroupInstance );
JsonConvert.DeserializeObject<SampleGroup>( sz, new SampleConverter());
Run Code Online (Sandbox Code Playgroud)

文档:使用CustomCreationConverter反序列化


小智 18

它非常简单,并且由json.net提供开箱即用的支持,您只需在序列化和反序列化时使用以下JsonSettings:

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

对于反序列化,请使用以下代码:

JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
    new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects}
);
Run Code Online (Sandbox Code Playgroud)

只需记下JsonSerializerSettings对象初始化程序,这对您很重要.


ada*_*sty 11

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

TypeNameHandling设置包括序列化JSON和读取类型信息时的类型信息,以便在反序列化JSON时创建创建类型

连载:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var text = JsonConvert.SerializeObject(configuration, settings);
Run Code Online (Sandbox Code Playgroud)

反序列化:

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

YourClass可能有任何类型的基类型字段,它将被正确序列化.


fer*_*ero 1

在我的项目中,这段代码始终充当默认序列化程序,它序列化指定的值,就好像没有特殊的转换器一样:

serializer.Serialize(writer, value);
Run Code Online (Sandbox Code Playgroud)

  • 序列化工作正常。问题在于反序列化为声明为接口的属性。实现 CustomCreationConverter 并将其传递给 JsonConvert.DeserializeObject 似乎是答案。 (3认同)