参考这个问题:
当然,很棒,但我可以吃蛋糕吗?
我正在寻找的是一种赏心悦目的方式,以一种字符可能包含的方式为一个属性提供一个替代名称.
就像是:
[BetterJsonProperty(PropertyName = "foo_bar")]
public string FooBar { get; set; }
Run Code Online (Sandbox Code Playgroud)
都
{
"FooBar": "yup"
}
Run Code Online (Sandbox Code Playgroud)
和
{
"foo_bar":"uhuh"
}
Run Code Online (Sandbox Code Playgroud)
将按预期反序列化.
由于没有属性的解决方案可以工作,或者类的属性如下:
[AllowCStylePropertyNameAlternatives]
Run Code Online (Sandbox Code Playgroud)
Bri*_*ers 28
实现此目的的一种方法是创建自定义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();
}
}
Run Code Online (Sandbox Code Playgroud)
要将自定义转换器与特定类一起使用,可以使用如下[JsonConverter]属性来装饰该类:
[JsonConverter(typeof(LaxPropertyNameMatchingConverter))]
public class MyClass
{
public string MyProperty { get; set; }
public string MyOtherProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
以下是转换器的简单演示:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
foo
bar
baz
quux
fizz
bang
Run Code Online (Sandbox Code Playgroud)
虽然这个解决方案应该在大多数情况下完成工作,但是如果您可以直接更改Json.Net源代码,那么可以使用更简单的解决方案.事实证明,通过向Newtonsoft.Json.Serialization.JsonPropertyCollection类中添加一行代码,您可以完成相同的任务.在这个类中,有一个方法GetClosestMatchProperty(),它看起来像这样:
public JsonProperty GetClosestMatchProperty(string propertyName)
{
JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal);
if (property == null)
property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase);
return property;
}
Run Code Online (Sandbox Code Playgroud)
在反序列化程序调用此方法的位置,JsonPropertyCollection包含要反序列化的类中的所有属性,并且该propertyName参数包含要匹配的JSON属性名称.如您所见,该方法首先尝试精确的名称匹配,然后尝试不区分大小写的匹配.因此,我们已经在JSON和类属性名称之间进行了多对一映射.
如果您修改此方法以在匹配之前从属性名称中去除所有非字母数字字符,那么您可以获得所需的行为,而无需任何特殊的转换器或属性.这是修改后的代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
当然,修改源代码也存在问题,但我认为值得一提.
小智 8
实现这一目标的另一种方法是尽早拦截序列化/反序列化过程,通过做一些覆盖JsonReader和JsonWriter
public class CustomJsonWriter : JsonTextWriter
{
private readonly Dictionary<string, string> _backwardMappings;
public CustomJsonWriter(TextWriter writer, Dictionary<string, string> backwardMappings)
: base(writer)
{
_backwardMappings = backwardMappings;
}
public override void WritePropertyName(string name)
{
base.WritePropertyName(_backwardMappings[name]);
}
}
public class CustomJsonReader : JsonTextReader
{
private readonly Dictionary<string, string> _forwardMappings;
public CustomJsonReader(TextReader reader, Dictionary<string, string> forwardMappings )
: base(reader)
{
_forwardMappings = forwardMappings;
}
public override object Value
{
get
{
if (TokenType != JsonToken.PropertyName)
return base.Value;
return _forwardMappings[base.Value.ToString()];
}
}
}
Run Code Online (Sandbox Code Playgroud)
执行此操作后,您可以执行序列化
var mappings = new Dictionary<string, string>
{
{"Property1", "Equivalent1"},
{"Property2", "Equivalent2"},
};
var builder = new StringBuilder();
JsonSerializer.Create().Serialize(new CustomJsonWriter(new StringWriter(builder), mappings), your_object);
Run Code Online (Sandbox Code Playgroud)
并通过执行反序列化
var mappings = new Dictionary<string, string>
{
{"Equivalent1", "Property1"},
{"Equivalent2", "Property2"},
};
var txtReader = new CustomJsonReader(new StringReader(jsonString), mappings);
var your_object = JsonSerializer.Create().Deserialize<Your_Type>(txtReader);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19813 次 |
| 最近记录: |