Newtonsoft Json сериализовать/десериализовать вложенное свойство

У меня есть следующая структура класса

public class MainClass
{
   public string MyStringValue {get;set;}
   public SecondClass MyClassValue {get;set;}
}

public class SecondClass
{
   public string Value {get;set;}
}

Я устанавливаю следующие значения:

SecondClass secondClass = new SecondClass
{
   Value = "Test"
}

MainClass mainClass = new MainClass
{
   MyStringValue = "String Value",
   MyClassValue = secondClass
}

Когда я сериализую класс mainClass, я получаю следующий Json (что для меня абсолютно ясно):

{
  "MyStringValue":"String Value",
  "MyClassValue":
  {
     "Value":"Test"
  }
}

Есть случаи, когда я хочу вместо этого сериализовать следующее:

{
  "MyStringValue":"String Value",
  "MyClassValue": "Test"
}

Имя поля подкласса всегда "Значение", как это можно сделать? (И мне также нужен десериализатор для той же структуры)


person Pinzi    schedule 21.02.2019    source источник


Ответы (4)


Один из способов добиться этого — использовать Custom JsonConverter с JsonConverterAttribute. Например, вы можете создать собственный преобразователь для своего класса:

public class SecondClassConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(SecondClass);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            if (reader.TokenType == JsonToken.String)
            {
                return new SecondClass
                {
                    Value = reader.Value.ToString()
                };
            }
        }
        catch (Exception ex)
        {
            throw new JsonSerializationException($"Error converting value {reader.Value} to type '{objectType}'.", ex);
        }

        throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing {nameof(SecondClass)}.");
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }

        var secondClass = (SecondClass)value;
        writer.WriteValue(secondClass.Value);
    }
}

И тогда вы бы использовали JsonConverterAttribute с этим преобразователем:

public class MainClass
{
    public string MyStringValue { get; set; }
    [JsonConverter(typeof(SecondClassConverter))]
    public SecondClass MyClassValue { get; set; }
}

public class SecondClass
{
    public string Value { get; set; }
}

Это позволит всем сериализациям MainClass использовать метод WriteJson SecondClassConverter:

static void Main(string[] args)
{
    SecondClass secondClass = new SecondClass
    {
        Value = "Test"
    };

    MainClass mainClass = new MainClass
    {
        MyStringValue = "String Value",
        MyClassValue = secondClass
    };

    var json = JsonConvert.SerializeObject(mainClass);

    Console.WriteLine(json);
    Console.ReadLine();
}

Предоставление желаемого результата JSON:

введите здесь описание изображения


И десериализация также будет работать, используя метод ReadJson SecondClassConverter:

static void Main(string[] args)
{
    var json = "{ \"MyStringValue\":\"String Value\", \"MyClassValue\": \"Test\" }";

    var decodedJson = JsonConvert.DeserializeObject<MainClass>(json);

    Console.WriteLine($"decodedJson.MyStringValue: {decodedJson.MyStringValue}");
    Console.WriteLine($"decodedJson.MyClassValue.Value: {decodedJson.MyClassValue.Value}");
    Console.ReadLine();
}

Предоставление вывода в виде:

введите здесь описание изображения

person devNull    schedule 21.02.2019
comment
спасибо, именно то, что я искал. Я добавил его в свою глобальную конфигурацию: settings.Converters.Add(new CustomEnumJsonConverter()); - person Pinzi; 23.02.2019

верхний json не совпадает с последним. Основной класс не может быть сериализован как {"MyStringValue":"String Value","MyClassValue": "Test"} без преобразования.

var resultObjet = new { 
     MyStringValue = mainClass.MyStringValue,
     MyClassValue = mainClass.SecondClass.MyClassValue
}

то вы можете сериализовать его.

person Derviş Kayımbaşıoğlu    schedule 21.02.2019

Для этого вам нужен новый класс для десериализации. Однако для сериализации вы можете просто создать анонимный тип на лету, например:

void Main()
{
    // import Newtonsoft.JsonConvert

    SecondClass secondClass = new SecondClass
    {
        Value = "Test"
    };

    MainClass mainClass = new MainClass
    {
        MyStringValue = "String Value",
        MyClassValue = secondClass
    };

    // The JSON as you expect
    var origJson = JsonConvert.SerializeObject(mainClass);
    Console.WriteLine(origJson);
    // The JSON Deserialized and the second class value outputted
    Console.WriteLine(JsonConvert.DeserializeObject<MainClass>(origJson).MyClassValue.Value);

    // The modified JSON as you wanted it
    var modJson = JsonConvert.SerializeObject(new { mainClass.MyStringValue, MyClassValue = mainClass.MyClassValue.Value });
    Console.WriteLine(modJson);

    // The modified JSON deserialized
    var deserialized = JsonConvert.DeserializeObject<ModMainClass>(modJson);
    Console.WriteLine(deserialized.MyStringValue);
}

public class ModMainClass
{
    public string MyStringValue { get; set; }
    public string MyClassValue { get; set; }
}

public class MainClass
{
   public string MyStringValue {get;set;}
   public SecondClass MyClassValue {get;set;}
}

public class SecondClass
{
    public string Value { get; set; }
} 
person Carlo Bos    schedule 21.02.2019

У вас есть два варианта, один из которых упоминал @Simonare

или измените structor вашего класса MainClass на

public class MainClass<T>
{
    public string MyStringValue { get; set; }
    public T MyClassValue { get; set; }
}

public class SecondClass
{
    public string Value { get; set; }
}

и теперь вы можете просто выбрать, что использовать в качестве MyClassValue

var c = new MainClass<string>();

Or

 var c = new MainClass<SecondClass>();
person Alen.Toma    schedule 21.02.2019