首页 > 解决方案 > 序列化后 Json.Net 属性名称更改

问题描述

假设我有一些我以前用 Json.Net 序列化过的类

public class BillingAddress
{
    public string BillingCity { get; set; }
    public string BillingState { get; set; }
    public string BillingStreet { get; set; }
    public string BillingZip { get; set; }
}

但是,我不得不返回并更改BillingStreetBillingStreet1,然后再更改为BillingStreetA。我正在尝试在 Json.Net 中找到一种方法来支持属性或自定义转换器,该转换器可以反序列化以前称为不同名称的属性,并且还支持具有多个不同的先前名称(例如在我的示例中) )。

我有一个依赖于属性的自定义转换器,如下所示:

[JsonVersionedPropertyName("BillingStreetA", "BillingStreet1")]
public string BillingStreet { get; set; }



public class VersionedPropertyNameConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        //return objectType.IsClass;
        return (objectType == typeof(IPaymentMethod));
    }

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object instance = objectType.GetConstructor(Type.EmptyTypes).Invoke(null);
        PropertyInfo[] props = objectType.GetProperties();
        var versionedProps = props.Where(x => Attribute.IsDefined(x, typeof(JsonVersionedPropertyName)));

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            foreach (var versProp in versionedProps)
            {
                var attrs = versProp.GetCustomAttributes(true);
                foreach (var att in attrs)
                {
                    var versionedProp = att as JsonVersionedPropertyName;
                    if (versionedProp != null)
                    {
                        var versions = versionedProp.VersionedNames;
                        PropertyInfo prop = props.FirstOrDefault(pi => 
                            pi.CanWrite && (string.Equals(pi.Name, jp.Name, StringComparison.OrdinalIgnoreCase) || versions.Contains(jp.Name)));
                        if (prop != null)
                            prop.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
                    }
                }
            }
        }

        return instance;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

但是,当我尝试将此转换器另一个转换器一起使用时,我的整个反序列化都失败了。我试图弄清楚是否有更好的方法来做到这一点(版本化的属性名称)而不是我上面的方法。

标签: c#jsonjson.net

解决方案


你很近。像这样的东西有效。我会把它作为一个练习来泛化它:):

public class OninaigConverter : JsonConverter
{
    private readonly Dictionary<string, string> _propertyMappings = new Dictionary<string, string>
    {
        {"BillingStreetA", "BillingStreet"},
        {"BillingStreet1", "BillingStreet"}
    };

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object instance = Activator.CreateInstance(objectType);
        var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            if (!_propertyMappings.TryGetValue(jp.Name, out var name))
                name = jp.Name;

            PropertyInfo prop = props.FirstOrDefault(pi =>
                pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);

            prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
        }

        return instance;
    }
}

推荐阅读