在 C# 中自定义 javascript 反序列化器

custom javascript deserializer in c#

我正在开发一个集成了浏览器的 C# 应用程序。 浏览器将以 json 格式向 C# 发送一些数据。

json 中的某些字段可以使用 javascript 反序列化器进行反序列化,但我有一些数据需要自定义反序列化器,我需要为此注册一个反序列化器,但事情是必须只为那些特殊数据调用自定义反序列化器,而必须为其他数据调用默认 javascript 反序列化器,可以从 C# 中目标字段的数据类型/名称识别特殊数据。我怎样才能做到这一点。

像这样。

public class example
{
  public string abc;
  public someOtherDataType xyz;

  public void example()
  {
    serializer = new JavaScriptSerializer();

    // receive json string

        serializer.RegisterConverters(new JavaScriptConverter[]
         { 
    new System.Web.Script.Serialization.CS.CustomConverter() 
    });

    //call deserializer

}
}

json 字符串类似于

{
"abc" : "valueabc"
"xyz" : "valueXYZ"
}

现在必须仅在反序列化 xyz 期间调用自定义反序列化器,并且必须为 abc 调用默认反序列化器。

谢谢。

这里的困难在于 JavaScriptConverter 允许您将 JSON 对象映射到 c# class -- 但在您的 JSON、"xyz" 只是一个字符串,不是一个对象。因此,您不能为 someOtherDataType 指定转换器,而必须为每个包含 someOtherDataType 实例的 class 指定转换器。

(请注意 Json.NET does not have this restriction. If you were willing to switch to that library you could write a JsonConverter 中的自定义转换器功能将 someOtherDataType 的所有使用与 JSON 字符串相互转换。)

写成这样JavaScriptConverter:

  1. 覆盖JavaScriptConverter.Deserialize
  2. 创建第二个 Dictionary<string, Object> 过滤掉需要自定义转换的字段。
  3. 调用 new JavaScriptSerializer.ConvertToType<T> 反序列化过滤字典中的标准字段。
  4. 手动转换剩余字段。
  5. SupportedTypes 覆盖为 return 容器类型。

因此,在您的示例中,您可以这样做:

public class example
{
    public string abc;
    public someOtherDataType xyz;
}

// Example implementation only.
public class someOtherDataType
{
    public string SomeProperty { get; set; }

    public static someOtherDataType CreateFromJsonObject(object xyzValue)
    {
        if (xyzValue is string)
        {
            return new someOtherDataType { SomeProperty = (string)xyzValue };
        }
        return null;
    }
}

class exampleConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new[] { typeof(example) }; }
    }

    // Custom conversion code below

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var defaultDict = dictionary.Where(pair => pair.Key != "xyz").ToDictionary(pair => pair.Key, pair => pair.Value);
        var overrideDict = dictionary.Where(pair => !(pair.Key != "xyz")).ToDictionary(pair => pair.Key, pair => pair.Value);

        // Use a "fresh" JavaScriptSerializer here to avoid infinite recursion.
        var value = (example)new JavaScriptSerializer().ConvertToType<example>(defaultDict);

        object xyzValue;
        if (overrideDict.TryGetValue("xyz", out xyzValue))
        {
            value.xyz = someOtherDataType.CreateFromJsonObject(xyzValue);
        }
        return value;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后,进行测试:

public class TestClass
{
    public static void Test()
    {
        // receive json string
        string json = @"{
""abc"" : ""valueabc"",
""xyz"" : ""valueXYZ""
}";
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new JavaScriptConverter[]
         { 
             new exampleConverter()
         });

        var example = serializer.Deserialize<example>(json);
        Debug.Assert(example.abc == "valueabc" && example.xyz.SomeProperty == "valueXYZ"); // No assert
    }
}