【问题标题】:Dynamic property name for serialization [duplicate]序列化的动态属性名称[重复]
【发布时间】:2018-05-28 11:27:49
【问题描述】:

我需要一个动态的属性名用于序列化。

public class Home
{
    public virtual int Id { get; set; } // value: 2

    public virtual string propertyName { get; set; } // value: administration

    public virtual string Text { get; set; } // value: text1
} 

应该序列化为:

{
  "Id": 2,
  "administration": "text1"
}

有什么方法可以序列化吗?哪个是反序列化它的最佳方法?

【问题讨论】:

  • 你可以使用一个元组Tuple<string,string>来存储一个属性的名称和值,如果你需要多个,你可以创建一个数组或元组列表
  • *多个值的更好方法是使用字典
  • 添加public string ToJson()
  • @MikeHjortChristensen 你这是什么意思?你能解释一下吗?谢谢 :)

标签: c# json.net


【解决方案1】:

根据 Rico Suter 关于如何Dynamically rename or ignore properties without changing the serialized class 的这篇文章,您可以添加一个扩展 DefaultContractResolver 的类,命名为 PropertyRenameAndIgnoreSerializerContractResolver

所以模型看起来像:

public class Home
{
    [JsonProperty("firstName")]
    public int Id { get; set; } // value: 2

    //public Dictionary<string,string> dictionary { get; set; }

    [JsonProperty("propertyName")]
    public string propertyName { get; set; } // value: administration

    [JsonIgnore]
    public string Text { get; set; } // value: text1
}

序列化看起来像这样:

var home = new Home();

home.Id = 2;
home.propertyName = "text1";

var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolver.RenameProperty(typeof(Home), "propertyName", "administration");

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;

var json = JsonConvert.SerializeObject(home, serializerSettings);

这给出了欲望的输出。

添加此类PropertyRenameAndIgnoreSerializerContractResolver.cs:

public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

    public PropertyRenameAndIgnoreSerializerContractResolver()
    {
        _ignores = new Dictionary<Type, HashSet<string>>();
        _renames = new Dictionary<Type, Dictionary<string, string>>();
    }

    public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
    {
        if (!_ignores.ContainsKey(type))
            _ignores[type] = new HashSet<string>();

        foreach (var prop in jsonPropertyNames)
            _ignores[type].Add(prop);
    }

    public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
    {
        if (!_renames.ContainsKey(type))
            _renames[type] = new Dictionary<string, string>();

        _renames[type][propertyName] = newJsonPropertyName;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (IsIgnored(property.DeclaringType, property.PropertyName))
            property.ShouldSerialize = i => false;

        if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
            property.PropertyName = newJsonPropertyName;

        return property;
    }

    private bool IsIgnored(Type type, string jsonPropertyName)
    {
        if (!_ignores.ContainsKey(type))
            return false;

        return _ignores[type].Contains(jsonPropertyName);
    }

    private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
    {
        Dictionary<string, string> renames;

        if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
        {
            newJsonPropertyName = null;
            return false;
        }

        return true;
    }
}

【讨论】:

    【解决方案2】:

    添加一个返回JObjectToJObject 方法。

    public JObject ToJObject()
    {
        JObject jObject = new JObject()
        {
            { "Id", Id },
            { propertyName, Text }
        }
    
        return jObject;
    }
    

    那么对于Deserializing,我可能会创建一个类似这样的工厂方法:

    public static Home CreateFromJObject(JObject obj)
    {
        Home h = new Home();
    
        foreach (var a in obj)
        {
            if (a.Key == "ID")
            {
                h.Id = a.Value.Value<int>();
            }
            else
            {
                h.propertyName = a.Key;
                h.Text = a.Value.Value<string>();
            }
        }
    
        return h;
    }
    

    因为如果那里有多个其他值,我要么将其更改为开关,要么确保仅在其中传递所需的 JObject。

    【讨论】:

    • 您有什么好主意如何将此对象反序列化回源模型?
    • 在答案中添加了工厂方法,这是众多方法之一。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多