如何重写JavaScriptSerializer.Deserialize<;T>;()

本文关键字:lt gt JavaScriptSerializer 何重写 重写 Deserialize | 更新日期: 2023-09-27 18:26:26

我得到一个json字符串,它几乎没有数据一致性问题。例如,json字符串中的一个字段返回字符串列表,而其他json字符串的同一字段返回字典(键、值对)。

我的类保存解析后的json值,该类的字段属性为List。由于这个数据一致性问题,json字符串无法正确解析。

以下是我解析json字符串的代码

 JavaScriptSerializer serializer = new JavaScriptSerializer();
 myClass mc = serializer.Deserialize<myClass>(jsonString);

有没有什么方法可以编写自定义代码来解析json字符串并将其映射到myClass?

如何重写JavaScriptSerializer.Deserialize<;T>;()

您没有给出您试图实现的目标的具体示例,这意味着我们需要自己编一个示例。考虑以下类别:

public class myClass
{
    public Dictionary<string, string> data { get; set; }
}

并考虑以下两个JSON字符串:

{"data": ["zero", 1, "two"]}
{"data": {"0": "zero", "1":1, "2":"two"}}

似乎您可能希望以相同的方式解析这些,将数组转换为键为数组索引的Dictionary<string, string>。这可以通过以下JavaScriptConverter:来实现

public class myClassConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var myClass = new myClass();
        object data;
        if (dictionary.TryGetValue("data", out data))
        {
            if (data.IsJsonArray())
            {
                myClass.data = data.AsJsonArray()
                    .Select((o, i) => new KeyValuePair<int, object>(i, o))
                    .ToDictionary(p => p.Key.ToString(NumberFormatInfo.InvariantInfo), p => serializer.ConvertToType<string>(p.Value));
            }
            else if (data.IsJsonObject())
            {
                myClass.data = data.AsJsonObject()
                    .ToDictionary(p => p.Key, p => serializer.ConvertToType<string>(p.Value));
            }
        }
        return myClass;
    }
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new [] { typeof(myClass) }; }
    }
}
public static class JavaScriptSerializerObjectExtensions
{
    public static bool IsJsonArray(this object obj)
    {
        if (obj is string || obj.IsJsonObject())
            return false;
        return obj is IEnumerable;
    }
    public static IEnumerable<object> AsJsonArray(this object obj)
    {
        return (obj as IEnumerable).Cast<object>();
    }
    public static bool IsJsonObject(this object obj)
    {
        return obj is IDictionary<string, object>;
    }
    public static IDictionary<string, object> AsJsonObject(this object obj)
    {
        return obj as IDictionary<string, object>;
    }
}

传递给Deserialize()IDictionary<string, object>对应于正在转换的JSON对象中的键/值对。对于一个特定的键(在这种情况下为"data"),如果该值是JSON对象,则object值将是IDictionary<string, object>;如果该值为JSON数组,则为IEnumerable(特别是ArrayList)。通过根据适当的类型测试值,可以进行转换。

转换器只执行反序列化。像这样使用:

        var jsonString1 = @"{""data"": [""zero"", 1, ""two""]}";
        var jsonString2 = @"{""data"": {""0"": ""zero"", ""1"":1, ""2"":""two""}}";
        var deserializer = new JavaScriptSerializer();
        deserializer.RegisterConverters(new JavaScriptConverter[] { new myClassConverter() });
        var newJson1 = new JavaScriptSerializer().Serialize(deserializer.Deserialize<myClass>(jsonString1));
        var newJson2 = new JavaScriptSerializer().Serialize(deserializer.Deserialize<myClass>(jsonString2));
        Console.WriteLine(newJson1); // Prints {"data":{"0":"zero","1":"1","2":"two"}}
        Console.WriteLine(newJson2); // Prints {"data":{"0":"zero","1":"1","2":"two"}}
        Debug.Assert(newJson1 == newJson2); // No assert