围绕已知类型的灵活性的另一面是它无法将相同的JSON字符串反序列化回原始类型 . 例如,假设我有一个简单的 Person 类:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
如果我创建 Dictinoary<string, object> 的实例并在序列化之前添加 Person 类的实例:
var dictionary = new Dictionary<string, object>();
dictionary.Add("me", new Person { Name = "Yan", Age = 30 });
var serializer = new new JavaScriptSerializer();
var json = serializer .Serialize(dictionary);
我将获得以下JSON {"me":{"Name":"Yan","Age":30}} ,它非常干净但没有任何类型信息 . 所以假设你有两个具有相同成员定义的类,或者如果 Person 是子类而没有引入任何其他成员:
public static class KnownTypeRegister
{
private static readonly ConcurrentBag _knownTypes = new ConcurrentBag();
public static void Add(Type type)
{
_knownTypes.Add(type);
}
public static IEnumerable Get()
{
return _knownTypes.ToArray();
}
}
添加一个静态构造函数,用寄存器注册类型:
[DataContract]
public class Person
{
static Person()
{
KnownTypeRegister.Add(typeof(Person));
}
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
}
在构造序列化程序时从寄存器中获取已知类型的数组:
var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());
更多动态/更好的选项是可能的,但他们're also more difficult to implement, if you want to read more about dynamic known type resolution, have a look at Juval Lowy'的MSDN文章主题here . 此外,Carlos Figueira的this blog post也详细介绍了更多先进技术,例如动态生成类型,非常值得您阅读主题!
如果你的WCF调用正在被ajax调用消耗,并且你把它放到 Javascript client just doesn't care. 那么为什么不让你的WCF调用只返回一个字符串?然后,WCF调用的内部可以使用JavaScriptSerializer序列化 Dictionary<string, object>
public string MyServiceMethod()
{
var hash = new Dictionary<string, object>();
hash.Add("key1", "val1");
hash.Add("key2", new { Field1 = "field1", Field2 = 42});
var serialized = new JavaScriptSerializer().Serialize(hash);
return serialized;
}
2 回答
NOTE: 我在答案开始时已经了解了很多关于JavaScriptSerializer的细节,如果您只是想了解原始问题中提到的已知类型问题的解决方案,请跳到答案的末尾 .
Performance
基于benchmarks我运行,JavaScriptSerializer比其他替代方案慢得多,与DataContractSerializer相比,可以花费2倍的时间来序列化/反序列化对象 .
No need for Known Type
也就是说,JavascriptSerializer更灵活,因为它没有提前知道类型,并且序列化的JSON至少在字典的情况下更清晰(参见示例here) .
围绕已知类型的灵活性的另一面是它无法将相同的JSON字符串反序列化回原始类型 . 例如,假设我有一个简单的
Person
类:如果我创建
Dictinoary<string, object>
的实例并在序列化之前添加Person
类的实例:我将获得以下JSON
{"me":{"Name":"Yan","Age":30}}
,它非常干净但没有任何类型信息 . 所以假设你有两个具有相同成员定义的类,或者如果Person
是子类而没有引入任何其他成员:那么序列化器根本无法保证JSON
{"Name":"Yan","Age":30}
可以被反序列化为正确的类型 .如果使用JavaScriptSerializer反序列化
{"me":{"Name":"Yan","Age":30}}
,则在字典中返回与"me"相关联的值不是Person
的实例,而是Dictionary<string, object>
,而不是一个简单的属性包 .如果你想得到一个
Person
实例,你可以(虽然你很可能永远不想!)使用ConvertToType
帮助方法转换Dictionary<string, object>
:另一方面,如果您不需要担心将这些JSON反序列化为正确的类型并且JSON serailization不是性能瓶颈(如果您还没有这样做,请查看代码并了解在序列化上花费了多少CPU时间)已经)然后我会说只使用JavaScriptSerializer .
Injecting Known Type
如果,在一天结束时,你仍然需要使用DataContractSerializer并需要注入那些KnownTypes,这里有两件事你可以试试 .
1)将已知类型的数组传递给DataContractSerializer constructor .
2)将DataContractResolver的子类(带有定位您感兴趣的类型的方法)传递给DataContractSerializer constructor
您可以创建一个“已知类型注册表”,它们可以跟踪可以添加到字典中的类型,如果您控制了需要注入DataContractSerializer的所有类型,您可以尝试最简单的事情:
KnownTypeRegister
类,以将类型添加到已知类型列表中:var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());
更多动态/更好的选项是可能的,但他们're also more difficult to implement, if you want to read more about dynamic known type resolution, have a look at Juval Lowy'的MSDN文章主题here . 此外,Carlos Figueira的this blog post也详细介绍了更多先进技术,例如动态生成类型,非常值得您阅读主题!
disclaimer 我不建议你在WCF endpoints 上公开
object
;虽然这似乎是'flexible'这不是一个好主意,因为你没有指定你的服务将提供什么样的信息 .现在回答
如果你的WCF调用正在被ajax调用消耗,并且你把它放到
Javascript client just doesn't care.
那么为什么不让你的WCF调用只返回一个字符串?然后,WCF调用的内部可以使用JavaScriptSerializer序列化Dictionary<string, object>
disclaimer2 这个是一种达到目的的手段(因为你问了这个问题) - 对于一个 生产环境 质量的应用程序,我会有一个定义良好的界面,因此很明显是什么被请求并通过网络发回 .