使用JavascriptSerializer

时间:2015-11-16 13:23:21

标签: c# .net json serialization

我有一个要序列化的数据类,它包含派生类的 IEnumerable 属性,但将它们存储为它们的基类:

public class ToSerializeClass
{
    public IEnumerable<BaseClass> DerivedClasses{ get; set; }

    public ToSerializeClass ()
        : base(ClassTypeEnum.TestClassType)
    {
    }
}

如果有帮助: ClassTypeEnum 枚举用于不同的目的,但如果有必要,它可以在以后识别派生类的类型,因为它被序列化(例如,如果我可以使用枚举字典和类型来解决我的问题)。

序列化成功完成,序列化类是所有预期派生类。所以,JSON字符串没问题。

问题是,当我尝试反序列化 ToSerializeClass 类的实例时,我必须为JavaScriptSerializer提供一个Type:

// sorry for the long names, trying to make it obvious
var deserialized = _serializer.Deserialize<BaseClass>(jsonStringOfIEnumerableBaseClasses);

由于我已将 BaseClass 作为Type提供,因此反序列化的结果是基类的集合,并且所有派生信息都将丢失。

如何反序列化 ToSerializeClass 实例以获得派生类的列表(IEnumerable)

我可以完全控制源代码,所以我可以修改我的数据类,必要时使用不同的集合,但是如果可能的话我想用JavaScriptSerializer来解决它。

谢谢!

1 个答案:

答案 0 :(得分:2)

您可以使用SimpleTypeResolver将类型信息嵌入到序列化的JSON中。

例如:

void Main()
{
    JavaScriptSerializer serializer = new JavaScriptSerializer(new SimpleTypeResolver());

    var original = new Container()
    {
        List = new List<A> { new A(), new B(), new C() }
    };

    var json = serializer.Serialize(original);
    var deserialized = serializer.Deserialize<Container>(json);

    Console.WriteLine(deserialized.List[0].GetType() == typeof(A)); // true
    Console.WriteLine(deserialized.List[1].GetType() == typeof(B)); // true
    Console.WriteLine(deserialized.List[2].GetType() == typeof(C)); // true
}

public class Container
{
    public IList<A> List
    { get; set; }
}
public class A
{ }
public class B : A
{ }
public class C : A
{ }

请注意,JSON会使用__type成员进行扩充,其中包含该类型的完全限定名称。所以JSON变得有些难看,例如在我的情况下(通过LINQPad运行):

{
  "__type": "UserQuery+Container, query_cxbxwu, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
  "List": [
    { "__type": "UserQuery+A, query_cxbxwu, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" },
    { "__type": "UserQuery+B, query_cxbxwu, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" },
    { "__type": "UserQuery+C, query_cxbxwu, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" }
  ]
}

当然,你也可以推出自己的JavaScriptTypeResolver,这可能会让你更漂亮。

例如,一个非常简单(但也不是很好)的实现可以只使用直接类名:

public class MyTypeResolver : JavaScriptTypeResolver
{
    public override Type ResolveType(string id)
    {
        return typeof(MyTypeResolver).Assembly.GetTypes().First(t => t.Name == id);
    }

    public override string ResolveTypeId(Type type)
    {
        return type.Name;
    }
}

生成的JSON会更加简单:

{
  "__type": "Container",
  "List": [
    { "__type": "A" },
    { "__type": "B" },
    { "__type": "C" }
  ]
}