Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
401 views
in Technique[技术] by (71.8m points)

json.net - Deserializing JSON to flattened class

I found the same question here...

Deserializing nested JSON structure to a flattened class with Json.NET using annotations

...but without a proper answer. One of the best suggestion is to wrap the nested object in a new class but this approach introduces another issue: lego name. In my example the most logic name for this class is the same name that parent class and of course is not possible. My example is simple, I just want to eliminate the "language" property in the parent class. Can somebody help me to do it?

using Newtonsoft.Json;

public partial class NamedType
{
    public string Name { get; set; }
}

public class Proficiency
{
    public string Level { get; set; }

    public string Name { get; set; }
}

public class Language
{
    public int Id { get; set; }

    public string Name { get; set; }

    //public Language Language { get; set; } //Compiler error
    //public Language Value { get; set; } //Not correct
    //public NamedType Language { get; set; } //Compiler error
    //public NamedType Value { get; set; } //Ugly, isn't?

    public Proficiency Proficiency { get; set; }
}

List<Language> languageList = JsonConvert.DeserializeObject<List<Language>>(json);

Example of json:

{
    "languages": [
        {
            "id": 1,
            "language": { "name": "Spanish" },
            "proficiency": {
                "level": "native_or_bilingual",
                "name": "Native or bilingual proficiency"
            }
        },
        {
            "id": 2,
            "language": { "name": "English" },
            "proficiency": {
                "level": "full_professional",
                "name": "Full professional proficiency"
            }
        },
        {
            "id": 3,
            "language": { "name": "Japanese" },
            "proficiency": {
                "level": "elementary",
                "name": "Elementary proficiency"
            }
        }
    ]
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In cases where JSON property names conflict with c# naming conventions, you can use DataMember or JsonProperty annotations to substitute a different name during serialization.

For instance, the following works with both DataContractJsonSerializer and Json.NET:

[DataContract]
public class Language
{
    [DataContract]
    class NamedType
    {
        [DataMember]
        public string name { get; set; }
    }

    [DataContract]
    class ProficiencyType
    {
        [DataMember]
        public string level { get; set; }
        [DataMember]
        public string name { get; set; }
    }

    [DataMember(Name="id")]
    public int Id { get; set; }

    [IgnoreDataMember] // Do not serialize this property
    public string Name { get; set; }

    [IgnoreDataMember]
    public string ProficiencyLevel { get; set; }

    [IgnoreDataMember]
    public string ProficiencyName { get; set; }

    [DataMember(Name="language")] // serialize this nested class property with name "language"
    [JsonProperty(ObjectCreationHandling=ObjectCreationHandling.Replace)] // When deserializing, always create a fresh instance instead of reusing the proxy class.
    NamedType LanguageName
    {
        get
        {
            return new NamedType { name = Name };
        }
        set
        {
            Name = (value == null ? null : value.name);
        }
    }

    [DataMember(Name = "proficiency")]
    [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
    ProficiencyType Proficiency
    {
        get
        {
            return new ProficiencyType { level = ProficiencyLevel, name = ProficiencyName };
        }
        set
        {
            ProficiencyLevel = (value == null ? null : value.level);
            ProficiencyName = (value == null ? null : value.name);
        }
    }
}

If you find the opt-in nature of DataContract attributes to be a nuisance and prefer to use Json.NET-specific attributes, then the following is equivalent:

public class Language
{
    class NamedType
    {
        public string name { get; set; }
    }

    class ProficiencyType
    {
        public string level { get; set; }
        public string name { get; set; }
    }

    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [JsonIgnore]
    public string Name { get; set; }

    [JsonIgnore]
    public string ProficiencyLevel { get; set; }

    [JsonIgnore]
    public string ProficiencyName { get; set; }

    [JsonProperty(PropertyName = "language", ObjectCreationHandling = ObjectCreationHandling.Replace)]
    NamedType LanguageName
    {
        get
        {
            return new NamedType { name = Name };
        }
        set
        {
            Name = (value == null ? null : value.name);
        }
    }

    [JsonProperty(PropertyName = "proficiency", ObjectCreationHandling = ObjectCreationHandling.Replace)]
    ProficiencyType Proficiency
    {
        get
        {
            return new ProficiencyType { level = ProficiencyLevel, name = ProficiencyName };
        }
        set
        {
            ProficiencyLevel = (value == null ? null : value.level);
            ProficiencyName = (value == null ? null : value.name);
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...