简体   繁体   English

我可以在不引用类型的情况下反序列化泛型吗?

[英]Can I deserialize generics without a reference to the type?

I am attempting to save/load a class to an xml file that contains generic types using a DataContractSerializer . 我正在尝试使用DataContractSerializer将类保存/加载到包含通用类型的xml文件中。 I have the save working, but have realized I can't load it because I don't have the list of knownTypes for the deserializer. 我有保存工作,但是意识到我无法加载它,因为我没有反序列化程序的knownTypes列表。

Is there a way of serializing/deserializing this class that would allow me to deserialize it without referencing any of the stored types directly? 有没有一种方法可以序列化/反序列化该类,从而使我可以对它进行反序列化而无需直接引用任何存储的类型?

Here is my SessionVariables class that I am trying to save/load: 这是我要保存/加载的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;
    }
}

The different modules of the application extend the ISessionVariables interface to create their own set of session variables, like this: 应用程序的不同模块扩展了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; }
}

And a singleton instance of the SessionVariables class is used to access session variables, like this: SessionVariables类的单例实例用于访问会话变量,如下所示:

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

I got the save working like this: 我的保存工作如下:

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

However this method does not work to deserialize the class because I don't know it's known types. 但是,此方法无法反序列化类,因为我不知道它是已知的类型。

Can I serialize and deserialize generic types when I don't have direct library references to any of the types used? 当我没有使用的任何类型的直接库引用时,可以序列化和反序列化泛型类型吗? And if so, how? 如果是这样,怎么办?

The problem here is that you aren't just wanting to serialize data, but you also want to serialize data about your data , ie, (cue the dramatic chipmunk) metadata . 这里的问题是您不仅要序列化数据,而且还想要序列化有关数据的数据 ,即(提示剧烈的花栗鼠) 元数据

That metadata, in this case, are the types of the models that held the data originally. 在这种情况下,该元数据是最初保存数据的模型的类型。 Normally, this isn't an issue, but as you've discovered if you're taking advantage of polymorphism in your design, your single collection may contain two or more different types, each of which needs to be deserialized to their original type. 通常,这不是问题,但是正如您所发现的,如果您在设计中利用了多态性,则单个集合可能包含两个或多个不同类型,每种类型都需要反序列化为其原始类型。

This is usually accomplished by saving this Type metadata to the serialized result. 通常,通过将此Type元数据保存到序列化结果中来实现。 Different serialization methods does this in different ways. 不同的序列化方法以不同的方式执行此操作。 Xaml serialization uses xml namespaces associated with .net namespaces, then names the elements after the original type name. Xaml序列化使用与.net命名空间关联的xml命名空间,然后在原始类型名称之后命名元素。 Json.net accomplishes this via a specific named value saved to the json object. Json.net通过保存到json对象中的特定命名值来实现此目的。

The default DataContractSerializer is not Type aware. 默认的DataContractSerializer不识别类型。 Therefore you need to replace it with a version that understands the .NET Type system and can serialize/deserialize Type metadata to the resulting xml. 因此,您需要将其替换为可以理解.NET Type系统并且可以将Type元数据序列化/反序列化为结果xml的版本。 Luckily, one already exists in the framework, the NetDataContractSerializer . 幸运的是,该框架中已经存在一个NetDataContractSerializer

And that's how you pad a link-only answer. 这就是您填充仅链接答案的方式。 The Aristocrats. 贵族。

You could accomplish this using a custom DataContractResolver. 您可以使用自定义DataContractResolver完成此操作。 This allows you to plug into the deserialization pipeline and provide a type to deserialize into based upon the type/namespace that is found in the serialized graph. 这使您可以插入反序列化管道,并根据序列化图中找到的类型/名称空间提供要反序列化的类型。

Here's a good article on it: http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/21/wcf-extensibility-data-contract-resolver.aspx 这是一篇不错的文章: http : //blogs.msdn.com/b/carlosfigueira/archive/2011/09/21/wcf-extensibility-data-contract-resolver.aspx

IDesign has an implementation of a resolver that can be used for dynamic discovery of types on their site: http://idesign.net/Downloads/GetDownload/1848 (you will probably have to make some modifications to handle generics) IDesign拥有一个解析程序的实现,可用于在其站点上动态发现类型: http : //idesign.net/Downloads/GetDownload/1848 (您可能必须进行一些修改才能处理泛型)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM