多个JsonProperty Name分配给单个属性

xqkwcwgp  于 2023-05-02  发布在  其他
关注(0)|答案(5)|浏览(195)

我有两种格式的JSON,我想反序列化到一个类。我知道我们不能将两个[JsonProperty]属性应用于一个属性。
你能建议我一个方法来实现这一点吗?

string json1 = @"
    {
        'field1': '123456789012345',
        'specifications': {
            'name1': 'HFE'
        }
    }";

string json2 = @"
    {
        'field1': '123456789012345',
        'specifications': {
            'name2': 'HFE'
        }
    }";

public class Specifications
{
    [JsonProperty("name1")]
    public string CodeModel { get; set; }
}

public class ClassToDeserialize
{
    [JsonProperty("field1")]
    public string Vin { get; set; }

    [JsonProperty("specification")]
    public Specifications Specifications { get; set; }        
}

我希望name1name2都被反序列化为规范类的name1属性。

waxmsbnn

waxmsbnn1#

一个不需要转换器的简单解决方案:只需添加第二个私有属性到您的类中,用[JsonProperty("name2")]标记它,并让它设置第一个属性:

public class Specifications
{
    [JsonProperty("name1")]
    public string CodeModel { get; set; }

    [JsonProperty("name2")]
    private string CodeModel2 { set { CodeModel = value; } }
}

小提琴:https://dotnetfiddle.net/z3KJj5

du7egjpx

du7egjpx2#

欺骗自定义JsonConverter对我很有效。Thanks@khaled4vokalz,@Khanh TO

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object instance = objectType.GetConstructor(Type.EmptyTypes).Invoke(null);
        PropertyInfo[] props = objectType.GetProperties();

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            if (string.Equals(jp.Name, "name1", StringComparison.OrdinalIgnoreCase) || string.Equals(jp.Name, "name2", StringComparison.OrdinalIgnoreCase))
            {
                PropertyInfo prop = props.FirstOrDefault(pi =>
                pi.CanWrite && string.Equals(pi.Name, "CodeModel", StringComparison.OrdinalIgnoreCase));

                if (prop != null)
                    prop.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
            }
        }

        return instance;
    }
fcy6dtqo

fcy6dtqo3#

您可以使用JsonConverter来执行此操作。
例如,当您使用来自第三方服务的一些数据时,它们会不断更改属性名称,然后返回到以前的属性名称,这很有用。:D
下面的代码演示如何将多个属性名反序列化为用[JsonProperty(PropertyName = "EnrollmentStatusEffectiveDateStr")]属性修饰的同一个类属性。
MediCalFFSPhysician也使用自定义的JsonConverter进行修饰:[JsonConverter(typeof(MediCalFFSPhysicianConverter))]
请注意,_propertyMappings字典保存了应该Map到EnrollmentStatusEffectiveDateStr属性的可能属性名称:

private readonly Dictionary<string, string> _propertyMappings = new()
{
    {"Enrollment_Status_Effective_Dat", "EnrollmentStatusEffectiveDateStr"},
    {"Enrollment_Status_Effective_Date", "EnrollmentStatusEffectiveDateStr"},
    {"USER_Enrollment_Status_Effectiv", "EnrollmentStatusEffectiveDateStr"}
};

完整代码:

// See https://aka.ms/new-console-template for more information
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Reflection;
using System.Text.Json;

internal class JSONDeserialization
{
    private static void Main(string[] args)
    {
        var jsonPayload1 = $"{{\"Enrollment_Status_Effective_Dat\":\"2022/10/13 19:00:00+00\"}}";
        var jsonPayload2 = $"{{\"Enrollment_Status_Effective_Date\":\"2022-10-13 20:00:00+00\"}}";
        var jsonPayload3 = $"{{\"USER_Enrollment_Status_Effectiv\":\"2022-10-13 21:00:00+00\"}}";

        var deserialized1 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload1);
        var deserialized2 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload2);
        var deserialized3 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload3);

        Console.WriteLine(deserialized1.Dump());
        Console.WriteLine(deserialized2.Dump());
        Console.WriteLine(deserialized3.Dump());

        Console.ReadKey();
    }
}

public class MediCalFFSPhysicianConverter : JsonConverter
{
    private readonly Dictionary<string, string> _propertyMappings = new()
    {
        {"Enrollment_Status_Effective_Dat", "EnrollmentStatusEffectiveDateStr"},
        {"Enrollment_Status_Effective_Date", "EnrollmentStatusEffectiveDateStr"},
        {"USER_Enrollment_Status_Effectiv", "EnrollmentStatusEffectiveDateStr"}
    };

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.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, Newtonsoft.Json.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;
    }
}

[JsonConverter(typeof(MediCalFFSPhysicianConverter))]
public class MediCalFFSPhysician
{
    [JsonProperty(PropertyName = "EnrollmentStatusEffectiveDateStr")]
    public string EnrollmentStatusEffectiveDateStr { get; set; }
}

public static class ObjectExtensions
{
    public static string Dump(this object obj)
    {
        try
        {
            return System.Text.Json.JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
        }
        catch (Exception)
        {
            return string.Empty;
        }
    }
}

输出如下:

改编自:Deserializing different JSON structures to the same C# class

qv7cva1a

qv7cva1a4#

我有同样的用例,虽然在Java中。
帮助https://www.baeldung.com/json-multiple-fields-single-java-field的资源
我们可以用一个

@JsonProperty("main_label_to_serialize_and_deserialize")
@JsonAlias("Alternate_label_if_found_in_json_will_be_deserialized")

在您的用例中,您可以

@JsonProperty("name1")
@JsonAlias("name2")
fcwjkofz

fcwjkofz5#

您甚至可以为两个以上的名称执行此操作。

@JsonProperty("name1")
@JsonAlias({"name2","name3","name4"})

相关问题