使用JavascriptSerializer将基类的IEnumerable反序列化为派生类

本文关键字:反序列化 派生 IEnumerable JavascriptSerializer 基类 使用 | 更新日期: 2023-09-27 18:22:08

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

public class ToSerializeClass
{
    public IEnumerable<BaseClass> DerivedClasses{ get; set; }
    public ToSerializeClass ()
        : base(ClassTypeEnum.TestClassType)
    {
    }
}

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

序列化成功完成,并且序列化的类都是预期的派生类。所以,JSON字符串是可以的。

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

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

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

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

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

谢谢!

使用JavascriptSerializer将基类的IEnumerable反序列化为派生类

您可以使用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" }
  ]
}