gpt4 book ai didi

c# - 反序列化时的备用属性名称

转载 作者:行者123 更新时间:2023-12-03 17:51:39 24 4
gpt4 key购买 nike

关于这个问题:

How can I change property names when serializing with Json.net?

当然,太好了,但是我可以吃蛋糕吗?

我正在寻找的是一种令人赏心悦目的方式,它以字符串可能包含其中任何一个的方式为属性提供备用名称。

就像是:

[BetterJsonProperty(PropertyName = "foo_bar")]
public string FooBar { get; set; }

两个都
{
"FooBar": "yup"
}


{     
"foo_bar":"uhuh"
}

会按预期反序列化。

作为没有属性的解决方案或类上的属性,如:
 [AllowCStylePropertyNameAlternatives]

最佳答案

实现此目的的一种方法是创建自定义 JsonConverter .这个想法是让转换器枚举我们感兴趣的对象的 JSON 属性名称,从名称中去除非字母数字字符,然后尝试通过反射将它们与实际对象属性匹配。下面是它在代码中的样子:

public class LaxPropertyNameMatchingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsClass;
}

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();

JObject jo = JObject.Load(reader);
foreach (JProperty jp in jo.Properties())
{
string name = Regex.Replace(jp.Name, "[^A-Za-z0-9]+", "");

PropertyInfo prop = props.FirstOrDefault(pi =>
pi.CanWrite && string.Equals(pi.Name, name, StringComparison.OrdinalIgnoreCase));

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();
}
}

要将自定义转换器与特定类一起使用,您可以使用 [JsonConverter] 装饰该类。属性是这样的:
[JsonConverter(typeof(LaxPropertyNameMatchingConverter))]
public class MyClass
{
public string MyProperty { get; set; }
public string MyOtherProperty { get; set; }
}

这是转换器运行的简单演示:
class Program
{
static void Main(string[] args)
{
string json = @"
[
{
""my property"" : ""foo"",
""my-other-property"" : ""bar"",
},
{
""(myProperty)"" : ""baz"",
""myOtherProperty"" : ""quux""
},
{
""MyProperty"" : ""fizz"",
""MY_OTHER_PROPERTY"" : ""bang""
}
]";

List<MyClass> list = JsonConvert.DeserializeObject<List<MyClass>>(json);

foreach (MyClass mc in list)
{
Console.WriteLine(mc.MyProperty);
Console.WriteLine(mc.MyOtherProperty);
}
}
}

输出:
foo
bar
baz
quux
fizz
bang

虽然这个解决方案在大多数情况下应该可以完成工作,但如果您同意直接更改 Json.Net 源代码的想法,还有一个更简单的解决方案。事实证明,您只需向 Newtonsoft.Json.Serialization.JsonPropertyCollection 添加一行代码即可完成相同的操作。类(class)。在这个类中,有一个方法叫做 GetClosestMatchProperty()看起来像这样:
public JsonProperty GetClosestMatchProperty(string propertyName)
{
JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal);
if (property == null)
property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase);

return property;
}

在解串器调用此方法时, JsonPropertyCollection包含来自被反序列化的类的所有属性,以及 propertyName参数包含要匹配的 JSON 属性名称的名称。如您所见,该方法首先尝试精确名称匹配,然后尝试不区分大小写的匹配。所以我们已经在 J​​SON 和类属性名称之间完成了多对一的映射。

如果您修改此方法以在匹配属性名称之前从属性名称中去除所有非字母数字字符,那么您可以获得所需的行为,而无需任何特殊转换器或属性。这是修改后的代码:
public JsonProperty GetClosestMatchProperty(string propertyName)
{
propertyName = Regex.Replace(propertyName, "[^A-Za-z0-9]+", "");
JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal);
if (property == null)
property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase);

return property;
}

当然,修改源代码也有问题,但我认为值得一提。

关于c# - 反序列化时的备用属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19873767/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com