Как я могу игнорировать свойства подкласса, которым я не владею во время сериализации? - PullRequest
2 голосов
/ 09 апреля 2019

У меня есть класс Tempo.Я могу свободно изменять:

public class Tempo
{
    public Period Period { get; set; }
    public int Value { get; set; } // in fact int should be a T here if it matters.

    // more properties here
}

Period - это класс из внешней зависимости, который я не могу изменить.

public class Period
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public int Count { get; set; }
    public string Foo { get; set; }

    // more properties here
}

Period - это огромный класс с множеством свойств, которыеЯ не хочу сериализоваться.Так что нет сладкого [JsonIgnore] для меня.С Period я хотел бы сохранить только свойства Start и End.

Я пытался использовать DefaultContractResolver безуспешно:

class TempoResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var props = base.CreateProperties(type, memberSerialization);
        return props
            .Where(p => p.PropertyName != "Period") // how to filter subclass?
            .ToList();
    }
}

Я пытался использоватьJsonConverter без успеха:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    var jo = new JObject();
    var type = value.GetType();
    jo.Add("type", type.Name);
    foreach (var prop in type.GetProperties().Where(x => x.CanRead))
    {
        object propVal = prop.GetValue(value, null);
        if (propVal != null)
        {
            jo.Add(prop.Name,
             JToken.FromObject(propVal, serializer));  // how to filter subclass?
        }
    }
    jo.WriteTo(writer);
}

В обоих случаях я не уверен, как фильтровать Period.Как я могу игнорировать свойства подкласса, которым я не владею во время сериализации?

Попробуйте онлайн!

Примечание:

  • Я использую C# 6
  • Я использую JSON.NET

Ответы [ 3 ]

2 голосов
/ 09 апреля 2019

Вы можете создать строго типизированный JsonConverter для Period класса:

public class PeriodConverter : JsonConverter<Period>
{
    public override void WriteJson(JsonWriter writer, Period period, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        writer.WritePropertyName(nameof(Period.Start));
        writer.WriteValue(period.Start);
        writer.WritePropertyName(nameof(Period.End));
        writer.WriteValue(period.End);
        writer.WriteEndObject();
    }

    public override Period ReadJson(JsonReader reader, Type objectType, Period existingValue, bool hasExistingValue,
        JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }
}

Использование:

var tempo = new Tempo
{
    Period = new Period
    {
        Start = DateTime.Now.AddDays(-1),
        End = DateTime.Now.AddHours(-1),
        Count = 42,
        Foo = "Foo"
    },
    Value = 42
};

var result = JsonConvert.SerializeObject(tempo, new PeriodConverter());
var regularJson = JsonConvert.SerializeObject(tempo);

regularJson будет иметь все свойства из Period:

{"Период": {"Начало": "2019-04-08T12: 21: 39.1525361 + 03: 00", "Конец": "2019-04-09T11: 21: 39.1535328 + 03: 00 "," Count ": 42," Foo ":" Foo "}," Value ": 42}

и result ожидается только:

{ "Период": { "Пуск": "2019-04-08T12: 21: 39,1525361 + 03: 00", "Конец": "2019-04-09T11: 21: 39,1535328 + 03: 00"}, "Значение": 42}

Обновление

Код в WriteJson можно упростить с помощью анонимного объекта:

public override void WriteJson(JsonWriter writer, Period period, JsonSerializer serializer)
{
    var token = JToken.FromObject(new {Start = period.Start, End = period.End});
    token.WriteTo(writer);
}
1 голос
/ 09 апреля 2019

Сделать подкласс:

public class Periodic
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

Использовать пользовательский конвертер с этим кодом:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    Periodic periodic = (Periodic)value;
    JToken t = JToken.FromObject(periodic);
    t.WriteTo(writer);
}
1 голос
/ 09 апреля 2019

Решением будет использование подмножества Period:

// your external dependency
public class Period
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public int Count { get; set; }
    public string Foo { get; set; }
}

// your copycat with only the properties you really need
public class Periodic
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

public class Tempo
{
    public Periodic Period { get; set; }
    public int Value { get; set; }
}

public static void Main()
{
    var period = new Period{Count = 1, Foo = "bar", Start = DateTime.Now, End = DateTime.Now.AddDays(1)};
    var tempo = new Tempo{Value = 1, Period = new Periodic {Start = period.Start, End = period.End} };

    Console.WriteLine(JsonConvert.SerializeObject(tempo));
}

Попробуйте онлайн!

Вы также можете использовать библиотеку, такую ​​как Automapper , чтобы обрабатывать сопоставление между внешним классом и подражателем. Для двух свойств это может быть немного излишним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...