在 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
:
- 覆盖
JavaScriptConverter.Deserialize
- 创建第二个
Dictionary<string, Object>
过滤掉需要自定义转换的字段。
- 调用
new JavaScriptSerializer.ConvertToType<T>
反序列化过滤字典中的标准字段。
- 手动转换剩余字段。
- 将
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
}
}
我正在开发一个集成了浏览器的 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
:
- 覆盖
JavaScriptConverter.Deserialize
- 创建第二个
Dictionary<string, Object>
过滤掉需要自定义转换的字段。 - 调用
new JavaScriptSerializer.ConvertToType<T>
反序列化过滤字典中的标准字段。 - 手动转换剩余字段。
- 将
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
}
}