【问题标题】:Can I deserialize generics without a reference to the type?我可以在不引用类型的情况下反序列化泛型吗?
【发布时间】:2013-11-27 14:34:23
【问题描述】:

我正在尝试使用DataContractSerializer 将类保存/加载到包含泛型类型的 xml 文件中。我有保存工作,但我意识到我无法加载它,因为我没有反序列化器的 knownTypes 列表。

有没有一种方法可以对此类进行序列化/反序列化,这样我就可以在不直接引用任何存储类型的情况下对其进行反序列化?

这是我正在尝试保存/加载的 SessionVariables 类:

[DataContract]
public class SessionVariables
{
    [DataMember]
    private Dictionary<Type, ISessionVariables> _sessionVariables = new Dictionary<Type, ISessionVariables>();
    private object _syncLock = new object();

    public T Get<T>()
        where T : ISessionVariables, new()
    {
        lock (_syncLock)
        {
            ISessionVariables vars = null;

            if (_sessionVariables.TryGetValue(typeof(T), out vars))
                return (T)vars;

            vars = new T();
            _sessionVariables.Add(typeof(T), vars);

            return (T)vars;
        }
    }

    public IList<Type> GetKnownTypes()
    { 
        IList<Type> knownTypes = new List<Type>();

        knownTypes.Add(this.GetType().GetType()); // adds System.RuntimeType

        foreach (Type t in _sessionVariables.Keys)
        {
            if (!knownTypes.Contains(t))
                knownTypes.Add(t);
        }

        return knownTypes;
    }
}

应用程序的不同模块扩展ISessionVariables 接口以创建自己的会话变量集,如下所示:

[DataContract]
public class ModuleASessionVariables : ISessionVariables
{
    [DataMember]
    public string ModuleA_Property1{ get; set; }
    [DataMember]
    public string ModuleA_Property2 { get; set; }
}


[DataContract]
public class ModuleBSessionVariables : ISessionVariables
{
    [DataMember]
    public string ModuleB_Property1{ get; set; }
    [DataMember]
    public string ModuleB_Property2 { get; set; }
}

SessionVariables 类的单例实例用于访问会话变量,如下所示:

singletonSessionVariables.Get<ModuleASessionVariables>().ModuleA_Property1
singletonSessionVariables.Get<ModuleBSessionVariables>().ModuleB_Property2

我的存档是这样的:

using (FileStream writer = new FileStream(@"C:\test.txt", FileMode.Create))
{
    DataContractSerializer dcs = new DataContractSerializer(typeof(SessionVariables), singletonSessionVariables.GetKnownTypes());
    dcs.WriteObject(writer, singletonSessionVariables);
    writer.Close();
}

但是,此方法无法反序列化该类,因为我不知道它是已知类型。

当我没有对所使用的任何类型的直接库引用时,我可以序列化和反序列化泛型类型吗?如果有,怎么做?

【问题讨论】:

  • :/ 我会使用 NetDataContractSerializer,它在结果中包含类型信息。
  • 不要认为这是可能的:如果类型本身是未知的,我们将如何创建一个类型的实例?
  • @Will 谢谢,我以前不知道它存在!你应该为此写一个答案:)
  • @Rachel:成功了吗?
  • @会不会是这样想的,我成功的将SessionVariables对象和子对象序列化和反序列化到一个文件中,无需提前指定类型,类型和数据就成功出来了。我遇到的唯一小问题是 _syncObject 在反序列化时被初始化为 null。我仍然需要测试将子对象移动到单独的程序集,并确保它可以在没有引用的情况下反序列化。

标签: c# .net-3.5 datacontractserializer


【解决方案1】:

这里的问题是,您不仅想要序列化数据,还想要序列化关于数据的数据,即(提示戏剧性的花栗鼠)元数据强>。

在这种情况下,元数据是最初保存数据的模型的类型。通常,这不是问题,但正如您发现的那样,如果您在设计中利用多态性,您的单个集合可能包含两个或多个不同的类型,每个类型都需要反序列化为其原始类型。

这通常通过将此 Type 元数据保存到序列化结果中来完成。不同的序列化方法以不同的方式做到这一点。 Xaml 序列化使用与 .net 命名空间关联的 xml 命名空间,然后以原始类型名称命名元素。 Json.net 通过保存到 json 对象的特定命名值来实现这一点。

默认的 DataContractSerializer 不支持类型。因此,您需要将其替换为能够理解 .NET 类型系统并且可以将类型元数据序列化/反序列化为生成的 xml 的版本。幸运的是,框架中已经存在一个,NetDataContractSerializer。

这就是您填充仅链接答案的方式。贵族。

【讨论】:

  • 效果很好,无需参考所需的外部模块库。我必须做的唯一更改是使用[DataMember] 属性标记_syncLock obejct,或者将其反序列化为null。我现在正在寻找解决方法。谢谢:)
【解决方案2】:

您可以使用自定义 DataContractResolver 来完成此操作。这允许您插入反序列化管道并根据在序列化图中找到的类型/命名空间提供反序列化类型。

这是一篇很好的文章: http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/21/wcf-extensibility-data-contract-resolver.aspx

IDesign 有一个解析器实现,可用于在其站点上动态发现类型:http://idesign.net/Downloads/GetDownload/1848(您可能需要进行一些修改以处理泛型)

【讨论】:

  • 请注意:此解决方案需要 .net 4——我刚刚注意到您问题中的 .net3-5 标签。
猜你喜欢
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 2010-12-25
相关资源
最近更新 更多