Pascal case dynamic properties with Json.NET 使用Json.NET进行Pascal case动态属性
Pascal case dynamic properties with Json.NET 使用Json.NET进行Pascal case动态属性
这是我的代码:
使用Newtonsoft.Json; var json = "{\"someProperty\":\"some value\"}"; dynamic deserialized = JsonConvert.DeserializeObject(json);
这个工作得很好:
Assert.That(deserialized.someProperty.ToString(), Is.EqualTo("some value"));
我希望这个也能工作(属性的首字母大写),但不改变json
:
Assert.That(deserialized.SomeProperty.ToString(), Is.EqualTo("some value"));
问题的出现原因是作者希望保留代码约定,但这会导致在JSON结构和逻辑类之间失去一致性。这可能会让开发人员感到困惑,因为他们期望保留JSON类,并且如果将来需要将数据重新序列化为相同的JSON格式,可能会出现问题。
解决方法是提前创建.NET类,然后使用带有设置的`DeserializeObject(string value, JsonSerializerSettings settings)`重载方法。需要将`JsonSerializerSettings`的`Binder`属性设置为自定义的`SerializationBinder`,在其中手动定义JSON类和预定义.NET类之间的关系。
也许可以在运行时生成帕斯卡命名的类,而不需要预先定义它们,但作者并没有深入研究JSON.NET的实现。可能可以通过使用`JsonSerializerSettings`的其他设置项之一(例如传递CustomCreationConverter)来实现,但作者不确定具体细节。
作者询问是否因为使用了`dynamic`类型而被认为是一个不好的想法。如果反序列化为`public class { public string SomeProperty { get; set; } }`,你是否仍然认为这是一个不好的想法,并且更喜欢属性使用小写驼峰命名(`someProperty`)。
回答是,这个问题的出现不只是因为使用了`dynamic`类型。问题在于在反序列化为契约时已经存在的编码约定。尽管如此,目前默认的MVC绑定器是不区分大小写的。
.NET中属性的大写约定是PascalCase,而我从JSON中获取的系统的约定是camelCase。我认为转换为PascalCase是最好的方法,我只是对你们中的很多人反对感到惊讶。
Pascal case dynamic properties with Json.NET(使用Json.NET实现帕斯卡命名法动态属性)问题的出现是因为需要将C#属性命名为帕斯卡命名法(Pascal case),而将JSON数据命名为小驼峰命名法(camel case)。解决方法是通过使用Json.NET提供的属性和MongoDB.Bson.Serialization.Conventions来实现。
对于Json.NET,可以通过在属性上添加[JsonProperty("schwabFirmId")]
特性来指定属性的JSON名称。
另一个更简单的方法是,如果你愿意引入MongoDB,可以尝试添加对MongoDB.Bson.Serialization.Conventions的引用。然后在模型的构造函数中添加以下代码:
var pack = new ConventionPack { new CamelCaseElementNameConvention(), new IgnoreIfDefaultConvention(true) }; ConventionRegistry.Register("CamelCaseIgnoreDefault", pack, t => true);
以上方法都可以保持C#属性的帕斯卡命名法,同时将JSON数据转换为小驼峰命名法。反序列化时,将传入的数据视为帕斯卡命名法,而序列化时会将其转换为小驼峰命名法。
Pascal case dynamic properties with Json.NET
在使用Json.NET处理JSON数据时,有时候需要将动态属性转换为Pascal Case(帕斯卡命名法)。下面是一种实现此功能的方法:
首先,需要使用ExpandoObject和自定义的ExpandoObjectConverter来实现。Json.NET已经提供了ExpandoObjectConverter,只需要稍作修改即可实现所需的功能。
在代码中,需要注意被添加了//CHANGED注释的地方,这些地方是进行了修改的地方。
下面是一个示例代码:
public class CamelCaseToPascalCaseExpandoObjectConverter : JsonConverter { //CHANGED //the ExpandoObjectConverter needs this internal method so we have to copy it //from JsonReader.cs internal static bool IsPrimitiveToken(JsonToken token) { switch (token) { case JsonToken.Integer: case JsonToken.Float: case JsonToken.String: case JsonToken.Boolean: case JsonToken.Null: case JsonToken.Undefined: case JsonToken.Date: case JsonToken.Bytes: return true; default: return false; } } ////// Writes the JSON representation of the object. /// /// Theto write to. /// The value. /// The calling serializer. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // can write is set to false } /// /// Reads the JSON representation of the object. /// /// Theto read from. /// Type of the object. /// The existing value of object being read. /// The calling serializer. /// The object value. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return ReadValue(reader); } private object ReadValue(JsonReader reader) { while (reader.TokenType == JsonToken.Comment) { if (!reader.Read()) throw new Exception("Unexpected end."); } switch (reader.TokenType) { case JsonToken.StartObject: return ReadObject(reader); case JsonToken.StartArray: return ReadList(reader); default: //CHANGED //call to static method declared inside this class if (IsPrimitiveToken(reader.TokenType)) return reader.Value; //CHANGED //Use string.format instead of some util function declared inside JSON.NET throw new Exception(string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting ExpandoObject: {0}", reader.TokenType)); } } private object ReadList(JsonReader reader) { IList
此外,还需要一个将字符串转换为Pascal Case的扩展方法,如下所示:
public static class StringExtensions { public static string ToPascalCase(this string s) { if (string.IsNullOrEmpty(s) || !char.IsLower(s[0])) return s; string str = char.ToUpper(s[0], CultureInfo.InvariantCulture).ToString((IFormatProvider)CultureInfo.InvariantCulture); if (s.Length > 1) str = str + s.Substring(1); return str; } }
有了以上的代码,就可以将动态属性转换为Pascal Case了。
使用示例代码如下:
var settings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = new List{ new CamelCaseToPascalCaseExpandoObjectConverter() } }; var json = "{\"someProperty\":\"some value\"}"; dynamic deserialized = JsonConvert.DeserializeObject (json, settings); Console.WriteLine(deserialized.SomeProperty); //some value var json2 = JsonConvert.SerializeObject(deserialized, Formatting.None, settings); Console.WriteLine(json == json2); //true
在这段示例代码中,使用了Json.NET提供的CamelCasePropertyNamesContractResolver将对象序列化为JSON时,属性名会被转换为驼峰命名法。如果不需要这个功能,可以省略这个设置。
以上就是实现将动态属性转换为Pascal Case的方法,希望对你有所帮助。