Как я могу "un-JsonIgnore" атрибут в производном классе?
Я использую JsonSerializer от Newtonsoft для сериализации некоторых классов.
Поскольку я хотел опустить одно поле моего класса в процессе сериализации, я объявил его следующим образом:
[JsonIgnore]
public int ParentId { get; set; }
Это сработало, но теперь я сталкиваюсь с новой проблемой: в производном классе я бы хотел, чтобы это поле появилось (и делаю это только в этом конкретном производном классе).
Я просматривал документацию и в интернете способ переопределить этот параметр в дочерних классах (наверное, мне нужно что-то вроде [JsonStopIgnore]
, но я не мог найти ничего близкого).
- Есть ли способ для меня, чтобы заставить
JsonSerializer
подобрать этот атрибут снова? - Можно ли явно пометить атрибут как
[JsonIgnore]
, но только в базовом классе?
5 ответов
Вы можете сделать это, создав пользовательский DefaultContractResolver
и переопределив его CreateProperty
метод.
Например, учитывая Foo
основа и производная Bar
:
public class Foo
{
[JsonIgnore]
public string Name { get; set; }
public int Age { get; set; }
}
public class Bar : Foo
{ }
Вы можете создать следующий обработчик контракта:
public class MyTypeContractResolver<T> : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member,
MemberSerialization
memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.Ignored = false;
property.ShouldSerialize = propInstance => property.DeclaringType != typeof (T);
return property;
}
}
Это установит все свойства в Ignored = false
и затем проанализируйте их по заданному предикату:
propInstance => property.DeclaringType != typeof (T);
Что в нашем случае означает "сериализацию следует выполнять только в том случае, если они не относятся к типу Foo
" (так как Фу является DeclaryingType
).
И затем, когда вы хотите десериализовать, вы передаете экземпляр решателя контракта в JsonSerializerSettings
:
var bar = new Bar();
var result = JsonConvert.SerializeObject(bar,
new JsonSerializerSettings {ContractResolver = new MyTypeContractResolver<Bar>()});
Единственный способ "переопределить" поведение [JsonIgnore]
атрибут заключается в том, чтобы использовать распознаватель контракта, как красиво объяснил @Yuval Itzchakov в своем ответе.
Однако есть и другое возможное решение, которое может работать на вас: вместо использования [JsonIgnore]
атрибут, вы могли бы реализовать ShouldSerializeParentId()
метод в ваших классах, чтобы контролировать, является ли ParentId
свойство сериализуется. В базовом классе верните этот метод false
; затем переопределите метод в производном классе для возврата true
, (Эта функция известна как условная сериализация свойств в Json.Net.)
public class Base
{
public int Id { get; set; }
public int ParentId { get; set; }
public virtual bool ShouldSerializeParentId()
{
return false;
}
}
public class Derived : Base
{
public override bool ShouldSerializeParentId()
{
return true;
}
}
Скрипка: https://dotnetfiddle.net/65sCSz
Я решил ту же проблему, используя ключевое слово new в свойстве производного класса.
public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
}
public class Bar: Foo
{
[JsonProperty("ParentId")]
public new int ParentId { get; set; }
}
Вы можете просто перезаписать ParentId
в производном классе.
public new int ParentId
{
get { return base.ParentId; }
set { base.ParentId = value; }
}
Я решил ту же проблему с помощью свойства ghost:
public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
[NotMapped]
public int FooParent { get; set; }
}
Когда я хочу показать это свойство всегда всегда скрытым, я заполняю его, в других случаях оно равно нулю:
Foos.ForEach(x => x.FooParent = ParentId);