【问题标题】:Serialize complex property of object as scalar value将对象的复杂属性序列化为标量值
【发布时间】:2016-07-22 09:59:54
【问题描述】:

假设我们有以下类定义

public class A
{
    public string Name { get; } = "Johny Bravo";
    public B ComplexProperty { get; } = new B();
}

public class B
{
    public string Prop1 { get; } = "value1";
    public string Prop2 { get; } = "value2";
    public int Prop3 { get; } = 100;

    public override string ToString()
    {
        return this.Prop3.ToString();
    }
}

序列化时

var a = new A();
var str = JsonConvert.SerializeObject(a);

会产生如下的json字符串

{
   "Name":"Johny Bravo",
   "ComplexProperty":{
      "Prop1":"value1",
      "Prop2":"value2",
      "Prop3":100
   }
}

我们如何将 ComplexProperty 序列化为标量值?期望的结果必须是这个:

{
   "Name":"Johny Bravo",
   "ComplexProperty":100
}

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    您的代码将无法编译,因为您将 B 类分配给 int 值 但我想我得到了你想要的:

     class Program
        {
    
    
        static void Main(string[] args)
        {
            var a = new A();
            var str = JsonConvert.SerializeObject(a);
            Console.Write(str);
        }
    }
    
    public class A
    {
        public string Name { get; } = "Johny Bravo";
        [JsonIgnore]
        public B ComplexProperty { get; } = new B();
        [JsonProperty("ComplexProperty")]
        public int complexValue => ComplexProperty.Prop3;
    }
    
    public class B
    {
        public string Prop1 { get; } = "value1";
        public string Prop2 { get; } = "value2";
        public int Prop3 { get; } = 100;
    
        public override string ToString()
        {
            return this.Prop3.ToString();
        }
    }
    

    由于您希望对象是平坦的(只有 1 级深度),因此您需要在 A 类上拥有该属性。由于您不想在 json 结果中包含您的复杂对象,因此您必须忽略它,并且由于您需要在 Json 结果中具有相同的名称,因此您必须告诉 json 序列化程序使用所需的序列化您的数据名字

    【讨论】:

    • 感谢您的回答。我确实想过类似的事情,但如果 A 和 B 来自第三方库怎么办?
    • @MihailShishkov 它没有任何区别。你有 get 方法,所以你可以有任何你想要的值。像 public int complexValue => SomeMethod(someObjects);
    • 在第 3 方库中有 A 和 B 意味着您不能更改他们的代码。因此,您不能只向它们添加新的属性或属性。如果我只是为了序列化而在 A 周围提供一个适配器,那么您的建议将起作用,这对我来说似乎是很多工作。想象一下,如果 A 是一个具有很多属性的真实类:)
    • 我找到了一种方法。检查我的答案。
    【解决方案2】:

    此问题的正确解决方案是使用可以处理您的类型的自定义JsonConverter。特别是在您无法控制 A 和 B 类的代码的情况下。这是示例代码

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var a = new A();
                var str = JsonConvert.SerializeObject(a, new JsonSerializerSettings()
                {
                    Converters = new List<JsonConverter>()
                    {
                        new BTypeJsonConverter()
                    }
                });
            }
        }
    
        public class A
        {
            public string Name { get; } = "Johny Bravo";
            public B ComplexProperty { get; } = new B();
        }
    
        public class B
        {
            public string Prop1 { get; } = "value1";
            public string Prop2 { get; } = "value2";
            public int Prop3 { get; } = 100;
    
            public override string ToString()
            {
                return this.Prop3.ToString();
            }
        }
    
        public class BTypeJsonConverter : JsonConverter
        {
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                var b = value as B;
                if (b == null) return;
                writer.WriteValue(b.ToString());
            }
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                JsonSerializer serializer)
            {
                throw new NotImplementedException();
            }
    
            public override bool CanConvert(Type objectType)
            {
                return objectType == typeof(B);
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      添加另一个属性并将序列化PropertyName 设置为第一个。如果您的类 A 来自第 3 方库,请创建一个派生自 A 的类并添加新属性。

      public class A
      {
          public string Name { get; } = "Johny Bravo";
      --> [JsonIgnore]
          public B ComplexProperty { get; } = new B();
       -->[JsonProperty(PropertyName = "ComplexProperty")]
      --> public string ComplexPropertyText { get{ return ComplexProperty.ToString(); } }
      }
      
      public class B
      {
          public string Prop1 { get; } = "value1";
          public string Prop2 { get; } = "value2";
          public int Prop3 { get; } = 100;
      
          public override string ToString()
          {
              return this.Prop3.ToString();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-20
        • 1970-01-01
        • 1970-01-01
        • 2017-11-25
        相关资源
        最近更新 更多