Я предоставлю это, сказав, что я знаю, в чем проблема, я просто не знаю, как ее решить. Я общаюсь с уровнем данных SOA.NET, который возвращает данные как JSON. Один из таких методов возвращает объект, в котором есть несколько коллекций. Объект в основном выглядит следующим образом:
{
"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, которые принимают конкретные параметры, но я не понял способ сделать это. Любые советы будут очень признательны!
Update:
Юваль Ицчаков предполагает, что этот вопрос, вероятно, дубликат, несколько верен (кажется). В указанной ссылке один из ответов на странице содержит то же решение, которое было предоставлено здесь. Я не заметил этого ответа, поскольку вопрос с ОП был другим, чем тот, который у меня был здесь. Виноват.
------- мое решение --------
Как я уже сказал: решение Matt заняло немного работы, но у меня есть что-то настроечное для меня. Единственное, что мне не понравилось в его первоначальном решении, были такие строки:
return objectType == typeof(ICog);
После этого шаблона вам понадобится JsonConverter для каждого абстрактного типа, который вы получаете по кабелю. В моей ситуации это не так идеально, поэтому я создал общий JsonConverter как таковой:
public class GenericJsonConverter<T>: JsonConverter, IBaseJsonConverter<T>
{
private readonly IUnityContainer Container;
public TalonJsonConverter(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), вы получите подозрительное предупреждение о броске в этом сценарии.
Надеюсь, кто-то найдет это полезным в будущем!