我很难解除对象的反序列化。它包含以下属性:
public List<IShape> Shapes { get; set; };
和JSON.NET反序列化器总是告诉我,实例化接口是不可能的。
我有几个类实现了实现IShape接口的接口,例如Polyline -> IPolyline -> IShape
。我已经尝试了两种解决方案:
但我得到了同样的例外,即IShape无法立即播出,被抛出。
我使用TypeNameHandling.Auto
序列化对象,TypeNameHandling.All
也没有帮助,即使我使用上面链接的帖子中提到的转换器。
有谁知道这个问题的解决方案?如果需要一些代码,我很乐意发布它。
以下是生成的JSON示例。
"$type": "SketchModel.Layer, SketchModel",
"Id": 57865477,
"Shapes": {
"$type": "System.Collections.Generic.List`1[[SketchModel.Shapes.AbstractShapes.IShape, SketchModel]], mscorlib",
"$values": [
{
"$type": "SketchModel.Shapes.Polyline, SketchModel",
此行负责解决问题:
"System.Collections.Generic.List`1[[SketchModel.Shapes.AbstractShapes.IShape, SketchModel]], mscorlib"
它根本不知道如何实例化IShape。如果我创建一个自定义转换器并让它返回每个IShape的折线,它可以工作,但不会创建任何其他形状(例如椭圆)。
在
在自定义转换器中覆盖的public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
方法,如果我让我打印objectType的完整类型名称,它总是IShape,从来没有其他任何东西......
答案 0 :(得分:2)
异常是有道理的,因为反序列化器不知道界面在保湿时应该表示的具体类型。
在序列化期间,JSON.NET允许您将其配置为添加一些要在这种情况下使用的元数据。 This SO question有一个答案解释如何配置它。
配置将向反序列化期间将使用的JSON添加类型属性。
答案 1 :(得分:1)
我确实遇到了这个问题,只是通过明确为Type提供转换器来解决它。如果我使用注释它不起作用 - 我需要在反序列化时传递转换器 - 基本上是这样的:
state = JsonConvert.DeserializeObject<StateImpl>((String)stateObject, new JsonConverter[] { new StatePersistenceStateEntryConverter(), new StatePersistenceUserInteractionConverter() });
我的StateImpl对象包含这些属性:
[DataMember]
[JsonProperty("stateEntries", TypeNameHandling = TypeNameHandling.Auto)]
public List<IStateEntry> StateEntries
{
get;
set;
}
[DataMember]
[JsonProperty("precommitStateEntry", TypeNameHandling = TypeNameHandling.Auto)]
public IPrecommitStateEntry PrecommitStateEntry
{
get;
set;
}
IPrecommitStateEntry扩展了IStateEntry接口(如果您想知道为什么转换器中有额外的逻辑,那么就是FYI。)
另外 - 在我的IStateEntry对象中,我有类似的孩子问题:
[DataMember]
[JsonProperty("userInteractions", TypeNameHandling = TypeNameHandling.Auto)]
public List<IUserInteraction> UserInteractions
{
get;
set;
}
因此我的对象具有IStateEntry的子列表属性,并且IStateEntry具有IUserInteraction的另一个子列表。我的转换器如下:
public class StatePersistenceStateEntryConverter : CustomCreationConverter<IStateEntry>
{
public override IStateEntry Create(Type objectType)
{
if (objectType == typeof(IPrecommitStateEntry))
{
return new PrecommitStateEntry();
}
else
{
return new StateEntry();
}
}
}
和...
public class StatePersistenceUserInteractionConverter : CustomCreationConverter<IUserInteraction>
{
public override IUserInteraction Create(Type objectType)
{
return new UserInteraction();
}
}
他们所做的一切就是创建特定对象实现的实例。
所以我不知道为什么需要转换器,因为可以清楚地实例化List - 而不是单独的IStateEntry。显然,NewtonSoft实现中存在一个错误 - 或者我缺少一些基本的东西。
希望有所帮助。对我来说这是一个令人沮丧的几个小时,但现在正在工作!
答案 2 :(得分:0)
在Json字符串中不包含具体类型,您可以使用JsonConverter
将IList<SomeInterface>
转换为具体类型:
public partial class MovieInfo : IMovieInfo
{
~~~~
[JsonProperty("genres")]
[JsonConverter(typeof(ListConverter<IGenre, Genre>))]
public IList<IGenre> Genres { get; set; }
~~~~
}
public class ListConverter<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)
{
JArray jsonArray = JArray.Load(reader);
var deserialized = (List<T>)Activator.CreateInstance(typeof(List<T>));
serializer.Populate(jsonArray.CreateReader(), deserialized);
return deserialized as IList<I>;
}
}