我计划建立一个返回通用字典对象序列化到JSON一个WCFservice。 不幸的是,序列化失败,因为对象是潜在的总是不同的。 KnownTypes不能帮助,因为属性类型是字典,我不能说KnownType,作为类将有可能永远不同。
如果有可能的任何想法序列化一个“未知类型”?
我不介意指定DataContract /数据成员每个我的课的,但(至少对于原型版本),我不希望有强大的类型为每一个响应。 JavaScript客户端只是不关心。
如何匿名类?
我计划建立一个返回通用字典对象序列化到JSON一个WCFservice。 不幸的是,序列化失败,因为对象是潜在的总是不同的。 KnownTypes不能帮助,因为属性类型是字典,我不能说KnownType,作为类将有可能永远不同。
如果有可能的任何想法序列化一个“未知类型”?
我不介意指定DataContract /数据成员每个我的课的,但(至少对于原型版本),我不希望有强大的类型为每一个响应。 JavaScript客户端只是不关心。
如何匿名类?
注:我已经到了很多关于JavaScriptSerializer细节在我的答案的开始,如果你只是想阅读有关决议,在原来的问题中提到的已知类型的问题,跳到答案结束。
性能
基于该基准我跑的JavaScriptSerializer比其它替代的慢得多,可以采取2倍,只要序列化/反序列化相比DataContractSerializer的一个对象。
无需已知类型
这就是说,JavascriptSerializer更加灵活,因为它不要求你指定“已知类型”时间提前,并序列化JSON是清洁至少在字典的情况下(见的例子在这里 )。
围绕已知类型的灵活性的另一面是,这将不能够反序列化同样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 class Employee : Person
{
}
再有就是根本没有办法让序列化能够保证JSON {"Name":"Yan","Age":30}
可序列化,以正确的类型。
如果反序列化{"me":{"Name":"Yan","Age":30}}
使用JavaScriptSerializer,在你回来关联的值字典“我”是不是一个实例Person
而是一个Dictionary<string, object>
,而不是一个简单的属性包。
如果你想获得一个Person
的实例回来,你可以(但你很可能会永远都不想!)转换是Dictionary<string, object>
使用ConvertToType
helper方法:
var clone = serializer.Deserialize<Dictionary<string, object>>(json);
var personClone = serializer.ConverToType<Person>(clone["me"]);
在另一方面,如果你并不需要担心反序列化JSON那些为正确的类型和JSON serailization不是一个性能瓶颈(分析代码并找出多少CPU时间的花费上的序列化,如果你还没有这样做已经),那么我会说只是使用JavaScriptSerializer。
注射已知类型
如果在一天结束时,你仍然需要使用DataContractSerializer的,需要注入这些KnownTypes,这里有两件事情你可以试试。
1)已知类型的数组传递给DataContractSerializer的构造 。
2)传递的一个子类DataContractResolver (的手段来定位类型感兴趣的你)DataContractSerializer的构造函数
您可以创建各种各样的“已知类型的注册表”,用于跟踪,可被添加到字典的类型,如果你控制,你需要注入到DataContractSerializer的所有类型,你可以尝试简单的事情:
创建KnownTypeRegister
用静态方法类的类型添加到已知类型的列表:
公共静态类KnownTypeRegister { 私人静态只读ConcurrentBag _knownTypes =新ConcurrentBag(); 公共静态无效的添加(型号类型) { _knownTypes.Add(类型); } 公共静态的IEnumerable的get() { 返回_knownTypes.ToArray(); } }
补充一点,与注册登记类型的静态构造函数:
[DataContract] 公共类Person { 静态的人() { KnownTypeRegister.Add(typeof运算(人)); } [数据成员] 公共字符串名称{; 组; } [数据成员] 公众诠释年龄{获得; 组; } }
从寄存器获取已知类型的数组,当你构建串行:
var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());
更多动态/更好的选择是可能的,但他们也更难以实现,如果你想了解更多有关动态已知类型解析,看看在话题朱瓦尔·洛的MSDN文章在这里 。 此外, 这篇博客文章由卡洛斯·费圭也将进入上更先进的技术细节,如动态生成的类型,非常值得一读,而你在话题!
免责声明我不”建议你揭露object
在WCF终结; 本书虽然这似乎“灵活”这不是一个好主意,因为你没有指定什么样的信息会被你的服务供应。
现在的答案
如果您的WCF呼叫正通过Ajax调用和消耗你把它Javascript client just doesn't care.
那么为什么不把你的WCF调用只是返回一个字符串? 然后,你的WCF呼叫的内部可以序列的Dictionary<string, object>
使用JavaScriptSerializer
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;
}
disclaimer2这是对目的的一种手段(因为你问的问题) -对于生产质量的应用程序我想有一个良好定义的接口,因此很明显是被要求什么,并送回了电线。