gpt4 book ai didi

c# - Json.NET 的 Pascal 大小写动态属性

转载 作者:可可西里 更新时间:2023-11-01 03:09:51 24 4
gpt4 key购买 nike

这是我的:

using 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"));

最佳答案

我同意 Avner Shahar-Kashtan 的观点。 你不应该这样做,尤其是当你无法控制 JSON 时。

也就是说,可以使用 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;
}
}

/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// can write is set to false
}

/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
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<object> list = new List<object>();

while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
default:
object v = ReadValue(reader);

list.Add(v);
break;
case JsonToken.EndArray:
return list;
}
}

throw new Exception("Unexpected end.");
}

private object ReadObject(JsonReader reader)
{
IDictionary<string, object> expandoObject = new ExpandoObject();

while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
//CHANGED
//added call to ToPascalCase extension method
string propertyName = reader.Value.ToString().ToPascalCase();

if (!reader.Read())
throw new Exception("Unexpected end.");

object v = ReadValue(reader);

expandoObject[propertyName] = v;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return expandoObject;
}
}

throw new Exception("Unexpected end.");
}

/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return (objectType == typeof (ExpandoObject));
}

/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
/// </summary>
/// <value>
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
/// </value>
public override bool CanWrite
{
get { return false; }
}
}

一个简单的字符串到 Pascal 大小写转换器。如果需要,让它更智能。

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

现在你可以像这样使用它了。

var settings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new List<JsonConverter> { new CamelCaseToPascalCaseExpandoObjectConverter() }
};

var json = "{\"someProperty\":\"some value\"}";

dynamic deserialized = JsonConvert.DeserializeObject<ExpandoObject>(json, settings);

Console.WriteLine(deserialized.SomeProperty); //some value

var json2 = JsonConvert.SerializeObject(deserialized, Formatting.None, settings);

Console.WriteLine(json == json2); //true

ContractResolver CamelCasePropertyNamesContractResolver在将对象序列化回 JSON 并再次使其成为 Camel 大小写时使用。这也是由 JSON.NET 提供的。如果你不需要这个,你可以忽略它。

关于c# - Json.NET 的 Pascal 大小写动态属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9247478/

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