我可以序列化Dictionary< string,object>吗?使用DataContract序列化器? [英] Can I serialize Dictionary<string, object> using DataContract serializer?

查看:91
本文介绍了我可以序列化Dictionary< string,object>吗?使用DataContract序列化器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正计划构建一个WCFservice,该服务返回序列化为JSON的通用字典对象.不幸的是,序列化失败,因为对象可能总是不同的.已知类型无济于事,因为属性类型是Dictionary,而我不能说KnownType,因为类可能总是不同的.

I'm planning to build a WCFservice that returns generic dictionary objects serialized to JSON. Unfortunately, serialization fails, as object is potentially always different. KnownTypes can't help, because property type is Dictionary, and I can't say KnownType, as the class will potentially be always different.

有什么想法可以序列化未知类型"吗?

Any ideas if it's possible to serialize an 'unknown type'?

我不介意为我的每个类指定DataContract/DataMember,但是(至少对于原型版本而言)我不想为每个响应都使用强类型. Javascript客户端根本不在乎.

I don't mind to specify DataContract/DataMember for each of my classes, but (at least for prototype version) I don't want to have strong types for each and every response. Javascript client just doesn't care.

匿名类怎么样?

推荐答案

注意:如果您想阅读的话,我会在我的答案的开头介绍有关JavaScriptSerializer的许多详细信息.关于原始问题中提到的已知类型问题的解决方案,请跳至答案结尾.

NOTE: I've gone into a lot of details about JavaScriptSerializer at the start of my answer, if you just want to read about the resolution to the known type problem mentioned in the original question, jump to the end of the answer.

性能

基于我运行的基准,JavaScriptSerializer的运行速度比其他替代方案慢得多,可能需要2倍的时间与DataContractSerializer相比,只要序列化/反序列化一个对象即可.

Based on the benchmarks I ran, the JavaScriptSerializer is the far slower than the other alternatives and can take 2x as long to serialize/deserialize an object compared to DataContractSerializer.

不需要已知类型

也就是说,JavascriptSerializer更加灵活,因为它不需要您提前指定已知类型",并且至少在字典的情况下,序列化的JSON更干净(请参见示例

That said, the JavascriptSerializer is more flexible in that it doesn't require you to specify 'known types' ahead of time, and the serialized JSON is cleaner at least in the case of dictionaries (see examples here).

围绕已知类型的灵活性的另一面是,它无法将相同的JSON字符串反序列化为原始类型.例如,假设我有一个简单的Person类:

The flip side of that flexibility around known types is that it won't be able to deserialize that same JSON string back to the original type. For instance, suppose I have a simple Person class:

public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }
}

如果我创建Dictinoary<string, object>的实例并将Person类的实例添加到它,然后再对其进行序列化:

And if I create an instance of Dictinoary<string, object> and add an instance of the Person class to it before serializing it:

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是子类的,而没有引入任何其他成员:

I'll get the following JSON {"me":{"Name":"Yan","Age":30}} which is very clean but devoid of any type information. So supposed if you have two classes with the same member definitions or if Person is subclassed without introducing any additional members:

public class Employee : Person
{
}

然后,串行器根本无法保证可以将JSON {"Name":"Yan","Age":30}反序列化为正确的类型.

then there's simply no way for the serializer to be able to guarantee that the JSON {"Name":"Yan","Age":30} can be deserialized to the correct type.

如果使用JavaScriptSerializer反序列化{"me":{"Name":"Yan","Age":30}},则在字典中您将获得与"me"关联的值不是Person的实例,而是Dictionary<string, object>的简单属性包.

If you deserialize {"me":{"Name":"Yan","Age":30}} using the JavaScriptSerializer, in the dictionary you get back the value associated with "me" is NOT an instance of Person but a Dictionary<string, object> instead, a simple property bag.

如果您想找回Person实例,则可以(尽管您很可能绝不想!)使用ConvertToType辅助方法将其转换为Dictionary<string, object>:

If you want to get a Person instance back, you could (though you most probably would never want to!) convert that Dictionary<string, object> using the ConvertToType helper method:

var clone = serializer.Deserialize<Dictionary<string, object>>(json);
var personClone = serializer.ConverToType<Person>(clone["me"]);

另一方面,如果您不必担心将这些JSON反序列化为正确的类型,并且JSON序列化不是性能瓶颈(分析您的代码,并找出序列化花费了多少CPU时间(如果您没有)还没有这样做),那么我想说的就是使用JavaScriptSerializer.

On the other hand, if you don't need to worry about deserializing those JSON into the correct type and JSON serailization is not a performance bottleneck (profile your code and find out how much CPU time's spent on serialization if you haven't done so already) then I'd say just use JavaScriptSerializer.

注入已知类型

如果最终,您仍然需要使用DataContractSerializer并注入那些KnownType,这是您可以尝试的两件事.

IF, at the end of the day, you do still need to use DataContractSerializer and need to inject those KnownTypes, here are two things you can try.

1)将已知类型的数组传递给DataContractSerializer 构造函数

1) Pass the array of known types to the DataContractSerializer constructor.

2)传递 DataContractResolver (使用定位您感兴趣的类型的方法)到DataContractSerializer 构造函数

2) Pass a subclass of DataContractResolver (with the means to locate the types of interest to you) to the DataContractSerializer constructor

您可以创建某种类型的已知类型注册表",以跟踪可以添加到字典中的类型,并且如果您控制需要注入到DataContractSerializer的所有类型,则可以尝试最简单的事情:

You can create a 'known type registry' of sorts that keeps track of the types that can be added to the dictionary, and if you control all the types that you'll need to inject to the DataContractSerializer, you can try the simplest thing:

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

  1. Create a KnownTypeRegister class with static methods to add a type to the list of known types:

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();
    }
}

  • 添加一个静态构造函数,用该寄存器注册类型:

  • Add a static constructor that registers the types with the register:

    [DataContract]
    public class Person
    {
        static Person()
        {
            KnownTypeRegister.Add(typeof(Person));
        }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
    }

  • 构造序列化器时,从寄存器中获取已知类型的数组:

  • Get the array of known types from the register when you construct the serializer:

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

    更多动态/更好的选项是可能的,但是它们也更难以实现,如果您想了解有关动态已知类型解析的更多信息,请参阅Juval Lowy在主题此博客文章 by Carlos Figueira还将详细介绍更先进的技术,例如动态生成类型,非常值得您在关注本主题的同时阅读!

    More dynamic/better options are possible but they're also more difficult to implement, if you want to read more about dynamic known type resolution, have a look at Juval Lowy's MSDN article on the topic here. Also, this blog post by Carlos Figueira also goes into details on more advance techniques such as dynamically generating the types, well worth a read whilst you're on the topic!

    这篇关于我可以序列化Dictionary&lt; string,object&gt;吗?使用DataContract序列化器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆