如何在序列化期间忽略我不拥有的子类的属性?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在序列化期间忽略我不拥有的子类的属性?相关的知识,希望对你有一定的参考价值。

我有一个班级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我想只保留StartEnd属性。

我试图使用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。如何在序列化期间忽略我不拥有的子类的属性?

Try it Online!

注意:

  • 我使用C#6
  • 我使用JSON.NET
答案

创建子类:

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);

另一答案

您可以为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”, “计数”: 42, “富”: “富”, “值”: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);

另一答案

解决方案是使用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 PeriodCount = 1, Foo = "bar", Start = DateTime.Now, End = DateTime.Now.AddDays(1);
    var tempo = new TempoValue = 1, Period = new Periodic Start = period.Start, End = period.End ;

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

Try it online!

您还可以使用像Automapper这样的库来处理外部类和模仿者之间的映射。对于两个属性,它可能有点矫枉过正。

以上是关于如何在序列化期间忽略我不拥有的子类的属性?的主要内容,如果未能解决你的问题,请参考以下文章

在使用 Jackson 反序列化期间选择性地忽略 JSON 属性

在 Java 中的 Jackson JSON 反序列化期间忽略丢失的属性

用于在反序列化期间忽略未知属性的 SpringMVC 全局设置

Jersey 2.8客户端在反序列化期间没有忽略未知属性

JSON 序列化程序如何忽略导航属性?

JSON 序列化程序如何忽略导航属性?