【问题标题】:DeSerialize to unknown derived type反序列化为未知的派生类型
【发布时间】:2013-07-11 14:36:57
【问题描述】:

我将一个序列化对象作为 json(或者将来可能是 xml)存储在数据库中。稍后,该对象将被拉取并反序列化。基类是 HighChart,但也有几个派生类型,例如 HighChart.ColumnBarChart。图表的类型存储在 JSON 中。问题是我无法弄清楚我将如何动态选择要反序列化的类。

我的解决方案需要提供一种自动考虑未来派生类型的方法(我将扩展图表类型的数量,并且不想为每种图表类型编写新的东西)。

我知道我可以将类型存储到单独的 DB 字段中 - 但我必须再次在我的 Deserialize 方法中为每种类型使用 switch 语句。我也可以解析 json 字符串并发现图表类型,但同样 - 我必须为每种可能的类型使用 switch 语句。

感谢您的意见!

【问题讨论】:

  • 我认为您不必将其反序列化为具体类型。您不能将其反序列化为基本类型,然后将其用作您需要的具体类型(强制转换)吗?
  • @BobHorn 我可以轻松地从派生类型转换为基类型,但我不能轻松地从基类型转换为派生类型(派生类型通常比基类型具有更多功能)也在此主题是这样的:stackoverflow.com/a/124347/1387186
  • 转换为基本类型时,不会丢失信息。它还在那里。您只是使用它作为基本类型。如果您强制转换为派生类型,您将可以访问派生属性。

标签: c# .net serialization deserialization


【解决方案1】:

如果您将新类型的Assembly Qualified Name 存储在数据库中,您将能够使用它来实例化该类型的实例,而无需更改类型加载代码。实现如下所示:

        string assemblyQualifiedName = getAssemblyQualifiedNameFromDatabase();

        var futureType = Type.GetType(assemblyQualifiedName);

        var serializer = new DataContractJsonSerializer(futureType);

        var result = (HighChart)serializer.ReadObject(stream);

请注意,没有 case 语句:无需提前知道实际类型。但是,此代码假定您已将新类型直接包含在项目中或通过引用包含在内。如果要使用尚未使用新类型引用重新编译的程序集动态加载新类型,则必须加载包含新类型的程序集并使用对已加载程序集的引用才能创建类型引用。

【讨论】:

    【解决方案2】:

    您提到您不能轻松地从基类型转换为派生类型。这是为什么?我能够这样做。我的 Dog 实体具有 Animal 基类型中不存在的属性 (DogYears),但我仍然可以将 Dog 反序列化为 Animal,然后将其强制转换并显示 DogYears。

    public class Dog : Animal
    {
        public int DogYears { get; set; }  // This doesn't exist in the base class
    
        public Dog()
        {
            this.DogYears = 4;
        }
    }
    

    在这里,我们将 Dog 序列化为基本类型,然后反序列化为基本类型,但我们仍然可以显示狗特定的属性:

    private static void JsonSerialization()
    {
        Animal dog = new Dog();
    
        var stream = new MemoryStream();
    
        var serializer = new DataContractJsonSerializer(typeof(Animal));
    
        serializer.WriteObject(stream, dog);
    
        stream.Position = 0;
    
        Animal deserializedDog = serializer.ReadObject(stream) as Animal;
    
        Console.WriteLine(((Dog)deserializedDog).DogYears);
    }
    

    控制台正确显示“4”。

    为了完整起见,这里是 Animal 类:

    [KnownType(typeof(Dog))]
    public abstract class Animal
    {
        // Properties here
    }
    

    【讨论】:

    • 当我使用 .NET 4.5 测试此代码时,我在 serializer.WriteObject 处遇到“类型不是预期的”异常。
    • 那是因为Animal 需要KnownType 属性。我已经编辑了我的问题以显示它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多