如何使用非标准(和可变)属性名(在.NET中)反序列化JSON

本文关键字:NET 反序列化 JSON 属性 何使用 非标准 | 更新日期: 2023-09-27 18:22:14

我必须读取JSON流(我无法控制),其形式为:

{"files":
    {
        "/some_file_path.ext": {"size":"1000", "data":"xxx", "data2":"yyy"},
        "/other_file_path.ext": {"size":"2000", "data":"xxx", "data2":"yyy"},
        "/another_file_path.ext": {"size":"3000", "data":"xxx", "data2":"yyy"},
    }
}

所以,我有一个名为files的对象,它有很多属性,1)每次都有不同的名称,2)每次都是不同数量的名称,3)名称中有不能在C#属性中使用的字符。

如何反序列化?

我把它放在一个可移植库中,所以我不能在System.Web.Script.Serialization中使用JavaScriptSerializer,而且我不确定JSON.NET。我希望使用标准的DataContractJsonSerializer。


更新:我更改了样本数据,使其更接近实际数据,并更正了不重要区域中的JSON语法。(仍然简化了很多,但其他部分相当标准)

如何使用非标准(和可变)属性名(在.NET中)反序列化JSON

您可以将"files"对象建模为由JSON属性名称键控的Dictionary

public class RootObject
{
    public Dictionary<string, PathData> files { get; set; }
}
public class PathData
{
    public int size { get; set; }
    public string data { get; set; }
    public string data2 { get; set; }
}

然后,仅当您使用.Net 4.5或更高版本时,您可以使用DataContractJsonSerializer进行反序列化,但必须首先设置DataContractJsonSerializerSettings.UseSimpleDictionaryFormat = true:

        var settings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true };
        var root = DataContractJsonSerializerHelper.GetObject<RootObject>(jsonString, settings);

使用辅助方法:

public static class DataContractJsonSerializerHelper
{
    public static T GetObject<T>(string json, DataContractJsonSerializer serializer = null)
    {
        using (var stream = GenerateStreamFromString(json))
        {
            var obj = (serializer ?? new DataContractJsonSerializer(typeof(T))).ReadObject(stream);
            return (T)obj;
        }
    }
    public static T GetObject<T>(string json, DataContractJsonSerializerSettings settings)
    {
        return GetObject<T>(json, new DataContractJsonSerializer(typeof(T), settings));
    }
    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }
}

或者,您可以安装Json.NET并执行以下操作:

        var root = JsonConvert.DeserializeObject<RootObject>(jsonString);

Json.NET自动将字典序列化为Json对象,而无需更改设置。

我们需要首先将此无效JSON转换为有效JSON。所以一个有效的JSON应该看起来像这个

{
    "files": 
    {
        "FilePath" : "C:''some''file''path",
        "FileData" : {
            "size": 1000,
            "data": "xxx",
            "data2": "yyy"
        },
        "FilePath" :"C:''other''file''path",
        "FileData" : {
            "size": 2000,
            "data": "xxx",
            "data2": "yyy"
        },
        "FilePath" :"C:''another''file''path",
        "FileData" : {
            "size": 3000,
            "data": "xxx",
            "data2": "yyy"
        }
    }
}

为了使其成为一个有效的JSON,我们可能会使用一些字符串函数使其看起来像上面所示。如

MyJSON = MyJSON.Replace("''", "''''");
MyJSON = MyJSON.Replace("files", "'"files'"");
MyJSON = MyJSON.Replace("data:", "'"data:'"");
MyJSON = MyJSON.Replace("data2", "'"data2'"");
MyJSON = MyJSON.Replace(": {size", ",'"FileData'" : {'"size'"");
MyJSON = MyJSON.Replace("C:", "'"FilePath'" :'"C:");

然后我们可以创建一个像下面这样的类来读取

public class FileData
{
    public int size { get; set; }
    public string data { get; set; }
    public string data2 { get; set; }
}
public class Files
{
    public string FilePath { get; set; }
    public FileData FileData { get; set; }
}
public class RootObject
{
    public Files files { get; set; }
}

假设您有一个有效的JSON,您可以使用JavaScriptSerializer返回对象列表

string json = "{}"
var serializer = new JavaScriptSerializer();
var deserializedValues = (Dictionary<string, object>)serializer.Deserialize(json, typeof(object));

或者,您可以指定Dictionary<string, List<string>>作为类型参数

strign json = "{}";
JavaScriptSerializer serializer = new JavaScriptSerializer();
var deserializedValues = serializer.Deserialize<Dictionary<string, List<string>>>(json);
foreach (KeyValuePair<string, List<string>> kvp in deserializedValues)
{
    Console.WriteLine(kvp.Key + ": " + string.Join(",", kvp.Value));
}