1

Suppose we have the following class definitions

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

when serialized

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

it will result in the following json string

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

How do we make the ComplexProperty serialize as scalar value? The desired result must be this one:

{
   "Name":"Johny Bravo",
   "ComplexProperty":100
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Mihail Shishkov
  • 14,129
  • 7
  • 48
  • 59

3 Answers3

3

Your code will not compile because you are assigning a B class to int value But I think I get what you want:

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

Since you want your object to be flat (only 1 level depth), you need to have the property on your A class. Since you don't want to have Your complex object in the json result, you have to ignore it, and since you need to have the same name on the Json results, you have to tell to json serializer to serialize your data with the required name

Ashkan S
  • 10,464
  • 6
  • 51
  • 80
  • Thanks for your answer. I did think of something like that but what if A and B come from a 3rd party library? – Mihail Shishkov Jul 22 '16 at 10:16
  • @MihailShishkov it doesn't make any difference. you have the get method, so you can have whatever value that you want. like public int complexValue => SomeMethod(someObjects); – Ashkan S Jul 22 '16 at 10:35
  • Having A and B in 3rd party library means that you can't change their code. Thus you can't just add new Attributes or Properties to them. Your suggestion will work if only I supply an adapter around A just for the sake of serialization which seems as a lot of work to me. Imagine if A is a real class with lot's of properties :) – Mihail Shishkov Jul 22 '16 at 10:40
  • I found a way to do that. Check my answer. – Mihail Shishkov Jul 22 '16 at 10:41
2

The proper solution to this problem is to use a custom JsonConverter that can handle your type. Especially in the case where you don't have control over the code of A and B classes. Here's the sample code

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);
        }
    }
}
Mihail Shishkov
  • 14,129
  • 7
  • 48
  • 59
0

Add another property and set the serializing PropertyName to first one. If your class A comes from a 3rd party library, create a class that derives from A and add the new property.

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();
    }
}
Nina
  • 1,035
  • 12
  • 17