c# - 使用 Json.net 序列化时如何根据类型更改属性名称?

标签 c# json attributes json.net

我有一个 object 类型的属性,我必须根据它的类型更改名称。应该非常相似 [XmlElement("PropertyName", typeof(PropertyType))] XML 属性。

例如,我有一个属性public object Item { get;放; }

如果在运行时我的属性的类型是Vehicle,我想将我的属性的名称更改为“Vehicle”;如果它的类型为 Profile ,我想将我的属性名称更改为“Profile”。

最佳答案

没有内置方法可以根据运行时类型动态更改属性名称,但您可以自定义 JsonConverter加上自定义 Attribute 类来做你想做的事。转换器需要在类级别运行,以便能够控制写入 JSON 的属性的名称。它可以使用反射遍历目标类的属性,并检查声明为 object 的任何属性是否应用了自定义属性。如果是,并且对象的运行时类型与属性中指定的类型匹配,则使用属性中的属性名称,否则只使用原始属性名称。

自定义属性如下所示:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
class JsonPropertyNameByTypeAttribute : Attribute
{
    public string PropertyName { get; set; }
    public Type ObjectType { get; set; }

    public JsonPropertyNameByTypeAttribute(string propertyName, Type objectType)
    {
        PropertyName = propertyName;
        ObjectType = objectType;
    }
}

这是转换器的代码:

public class DynamicPropertyNameConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Type type = value.GetType();
        JObject jo = new JObject();

        foreach (PropertyInfo prop in type.GetProperties().Where(p => p.CanRead))
        {
            string propName = prop.Name;
            object propValue = prop.GetValue(value, null);
            JToken token = (propValue != null) ? JToken.FromObject(propValue, serializer) : JValue.CreateNull();

            if (propValue != null && prop.PropertyType == typeof(object))
            {
                JsonPropertyNameByTypeAttribute att = prop.GetCustomAttributes<JsonPropertyNameByTypeAttribute>()
                    .FirstOrDefault(a => a.ObjectType.IsAssignableFrom(propValue.GetType()));

                if (att != null)
                    propName = att.PropertyName;
            }

            jo.Add(propName, token);
        }

        jo.WriteTo(writer);
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // ReadJson is not called if CanRead returns false.
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        // CanConvert is not called if a [JsonConverter] attribute is used
        return false;
    }
}

要使用转换器,首先要将 [JsonConverter] 属性添加到包含要动态命名的属性(或多个属性)的目标类。然后,将自定义属性添加到该类中的一个或多个目标属性。您可以根据需要添加尽可能多的属性,以涵盖您期望的类型范围。

例如:

[JsonConverter(typeof(DynamicPropertyNameConverter))]
class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonPropertyNameByType("Vehicle", typeof(Vehicle))]
    [JsonPropertyNameByType("Profile", typeof(Profile))]
    public object Item { get; set; }
}

然后,像往常一样序列化:

string json = JsonConvert.SerializeObject(foo, Formatting.Indented);

这是一个工作演示:https://dotnetfiddle.net/75HwrV

关于c# - 使用 Json.net 序列化时如何根据类型更改属性名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44577850/

相关文章:

c# - 线程合并排序比串行实现慢

c# - 为什么 WPF 使用 HTML/HEX 颜色?

javascript - 如何使用 angularjs、Django、Django Rest 框架更新模型

python - 在不创建对象的情况下使用python中类的属性

c# - 在运行时未发生在对象上添加属性

sockets - 有人可以解释一下 "from socket import example"和 "import socket"之间的区别吗?

c# - 根据值操作 div

c# - 如果未选中 DataGridColumn/Row 中的任何复选框,则显示 MessageBox

java - 在 java 中使用谷歌的 gson 解析 JSON 输出

javascript - 使用 D3 逐节点构建图