【发布时间】:2014-07-09 02:24:29
【问题描述】:
我会先说我知道问题出在哪里,只是不知道如何解决它。我正在与以 JSON 形式返回数据的 .NET SOA 数据层进行通信。一种这样的方法返回一个包含多个集合的对象。对象基本上是这样的:
{
"Name":"foo",
"widgetCollection":[{"name","foo"}, {"name","foo"},],
"cogCollection": [{"name","foo"}, {"childCogs",<<new collection>>},],
}
代表这个对象的类如下所示:
public class SuperWidget : IWidget
{
public string Name { get; set; }
public ICollection<IWidget> WidgetCollection { get; set; }
public ICollection<ICog> CogCollection { get; set; }
public SuperWidget()
{
}
[JsonConstructor]
public SuperWidget(IEnumerable<Widget> widgets, IEnumerable<Cog> cogs)
{
WidgetCollection = new Collection<IWidget>();
CogCollection = new Collection<ICog>();
foreach (var w in widgets)
{
WidgetCollection.Add(w);
}
foreach (var c in cogs)
{
CogCollection.Add(c);
}
}
}
这个构造函数工作正常,直到 cogCollection 添加了一个子集合,现在我得到了上述错误。具体的 cog 类如下所示:
[Serializable]
public class Cog : ICog
{
public string name { get; set; }
public ICollection<ICog> childCogs { get; set; }
}
我不想将集合更改为具体类型,因为我使用的是 IoC。因为我使用的是 IoC,所以我真的很想摆脱让 JsonConstructors 接受具体参数的需要,但我还没有找到一种方法来做到这一点。任何建议将不胜感激!
更新:
Yuval Itzchakov 关于这个问题可能是重复的建议在某种程度上是正确的(似乎)。在引用的帖子中,页面下方的答案之一提供了与此处提供的相同解决方案。我没有注意到那个答案,因为 OP 的问题与我在这里的问题不同。我的错。
-------我的解决方案--------
正如我所说:Matt 的解决方案需要做一些工作,但我得到了一些适合我的设置。我不喜欢他最初的解决方案的一件事是这样的:
return objectType == typeof(ICog);
按照这种模式,您需要为通过网络接收的每个抽象类型都有一个 JsonConverter。这在我的情况下不太理想,所以我创建了一个通用的 JsonConverter:
public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T>
{
private readonly IUnityContainer Container;
public GenericJsonConverter(IUnityContainer container)
{
Container = container;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var target = serializer.Deserialize<Newtonsoft.Json.Linq.JObject>(reader);
var result = Container.Resolve<T>();
serializer.Populate(target.CreateReader(), result);
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
然后在我反序列化我的数据之前,我会做这样的事情:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
settings.Converters.Add((JsonConverter)Container.Resolve<IBaseJsonConverter<ICog>>());
Protip:如果你使用 Resharper,(JsonConverter) 在这种情况下会给你一个可疑的演员表警告。
希望其他人在以后发现这很有用!
【问题讨论】:
-
尝试使用
JsonSerializerSettings类的TypeNameHandling.All并将其传递给json序列化程序