Как я могу "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);
Другие вопросы по тегам