我可以序列字典 使用DataContract串行?(Can I serialize Dicti

2019-09-16 18:56发布

我计划建立一个返回通用字典对象序列化到JSON一个WCFservice。 不幸的是,序列化失败,因为对象是潜在的总是不同的。 KnownTypes不能帮助,因为属性类型是字典,我不能说KnownType,作为类将有可能永远不同。

如果有可能的任何想法序列化一个“未知类型”?

我不介意指定DataContract /数据成员每个我的课的,但(至少对于原型版本),我不希望有强大的类型为每一个响应。 JavaScript客户端只是不关心。

如何匿名类?

Answer 1:

注:我已经到了很多关于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的所有类型,你可以尝试简单的事情:

  1. 创建KnownTypeRegister用静态方法类的类型添加到已知类型的列表:

      公共静态类KnownTypeRegister  {      私人静态只读ConcurrentBag _knownTypes =新ConcurrentBag();      公共静态无效的添加(型号类型)      {          _knownTypes.Add(类型);      }      公共静态的IEnumerable的get()      {          返回_knownTypes.ToArray();      }  } 
  2. 补充一点,与注册登记类型的静态构造函数:

      [DataContract]  公共类Person  {      静态的人()      {          KnownTypeRegister.Add(typeof运算(人));      }      [数据成员]      公共字符串名称{;  组;  }      [数据成员]      公众诠释年龄{获得;  组;  }  } 
  3. 从寄存器获取已知类型的数组,当你构建串行:

var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());

更多动态/更好的选择是可能的,但他们也更难以实现,如果你想了解更多有关动态已知类型解析,看看在话题朱瓦尔·洛的MSDN文章在这里 。 此外, 这篇博客文章由卡洛斯·费圭也将进入上更先进的技术细节,如动态生成的类型,非常值得一读,而你在话题!



Answer 2:

免责声明我不”建议你揭露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这是对目的的一种手段(因为你问的问题) -对于生产质量的应用程序我想有一个良好定义的接口,因此很明显是被要求什么,并送回了电线。



文章来源: Can I serialize Dictionary using DataContract serializer?