【发布时间】:2021-07-21 18:49:27
【问题描述】:
为了问我的问题,我将参考@Brian Rogers 的回答here。 在这个答案中,ReadJson 正在做一些相对简单的事情。但是,我如何在其中添加一个层,以便在将传入的 Json 字符串反序列化为对象然后返回之前对其进行操作?
这是我想做的事情的类型(Brian 的 WrappedObjectConvert 类的修改版本):
class WrappedObjectConverter : JsonConverter
{
private string CustomParsing(string jsonString)
{
string modifiedJsonString;
// Some renaming
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CarName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CustName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")MyName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")SomeAddr(?="":\s)", "AddressLine1 ", RegexOptions.IgnoreCase);
// Renaming IsPublic true/false to IsPrivate false/true
modifiedJsonString= Regex.Replace(modifiedJsonString, "\"IsPublic\": true,", "\"IsPrivate\": false,", RegexOptions.IgnoreCase);
modifiedJsonString = Regex.Replace(modifiedJsonString, "\"IsPublic\": false,", "\"IsPrivate\": true,", RegexOptions.IgnoreCase);
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
string modifiedJsonString = CustomParsing(token.ToString());
return ????; // How to return the object
// I could do something of the sort, but not sure it's got its place here:
// return JsonConvert.DeserializeObject<RootObject>(modifiedJsonString );
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
客户端类也稍作修改,添加了“IsPrivate”字段:
public class Client
{
[JsonConverter(typeof(WrappedObjectConverter))]
public List<Product> ProductList { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public string Name { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public bool IsPrivate { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public string AddressLine1 { get; set; }
}
还有修改过Json的demo(Brian的例子中有些标签已经改了,需要解析修改):
class Program
{
static void Main(string[] args)
{
string json = @"
{
""Result"": {
""Client"": {
""ProductList"": {
""Product"": [
{
""MyName"": {
""CarName"": ""Car polish"",
""IsPublic"": ""True""
}
}
]
},
""MyName"": {
""CustName"": ""Mr. Clouseau""
},
""AddressLine1"": {
""SomeAddr"": ""Hightstreet 13""
}
}
}
}";
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
Client client = obj.Result.Client;
foreach (Product product in client.ProductList)
{
Console.WriteLine(product.Name);
}
Console.WriteLine(client.Name);
Console.WriteLine(client.AddressLine1);
}
}
如您所见,解析的方式有点老套,所以我的问题是:
- 我能否在不弄乱我的类的情况下将此解析合并到类本身?
- 如果我的方法是可行的方法,我如何重新创建对象以便 ReadJson() 可以返回它(请参阅 上面代码中的问号)
- 更上一层楼:如果客户端类有一个构造函数接受参数(传递给基类),你会怎么做 2。(因为我相信额外的嵌套级别会使事情复杂化)
- 如果这是错误的方法,我愿意接受建议
【问题讨论】:
-
我不确定,但在我看来,您最终会尝试将一些深度嵌套的 JSON 扁平化为更简单的结构。你已经找到了一个我写的转换器,但是没有达到你想要的程度,所以你的解决方案是尝试使用正则表达式操作 JSON 以使其适合转换器(这不是一个好方法,IMO) .我认为您可能正在寻找的是Can I specify a path in an attribute to map a property in my class to a child property in my JSON?。如果我误解了,请澄清。
-
你理解正确@BrianRogers,谢谢。我同意使用正则表达式很麻烦,我确实在寻找一种替代方法。从您的链接中,您是否必须用“[JsonProperty("...")]" 装饰每个 Json 属性?添加所有这些硬编码的名称不是维护责任吗?使用自定义 SerializationBinder 以便所有硬编码名称都集中在那里不是更好吗?如果没有,为什么不呢?
-
@BrianRogers,Activator.CreateInstance(objectType) 也失败了,因为我的对象没有无参数构造函数。
-
使用另一个答案中的
JsonPathConverter,您只需要装饰那些名称与 JSON 中的名称不同或需要映射到子对象的属性。但是根据您的限制,此转换器也不适合您。它不会处理非默认构造函数(如您所见),并且对于IsPublic属性示例,它没有办法将 true 转换为 false,反之亦然。您将需要一个专门针对您的情况的自定义转换器。 -
A
SerializationBinder不会将 JSON 属性映射到类属性,它会将 JSON 中的类型名称和程序集名称(在特殊的$type元属性中)映射到实际类型。所以这对扁平化没有帮助。
标签: c# json parsing jsonconvert