Xml序列化:不能序列化来自另一个程序集的对象

时间:2022-06-26 03:10:48

I'm trying to XML serialize/deserialize an object in C#. The catch is that this object is of a type that was not declared in the same assembly as the code that is invoking the serialization. Instead, it comes from an assembly loaded dynamically at runtime, ant thus it is unknown at compilation time to the code that is invoking the serialization.

我正在尝试XML序列化/反序列化c#中的对象。问题是该对象的类型与调用序列化的代码在同一程序集中没有声明。相反,它来自运行时动态加载的程序集,ant因此在编译时对调用序列化的代码来说是未知的。

The type I'm trying to serialize is this:

我要序列化的类型是:

//Assembly = P.dll
namespace EDFPlugin.Plugin1
{
    [Serializable]
    [XmlRoot(Namespace = "EDFPlugin.Plugin1")] 
    [XmlInclude(typeof(Options))] 
    public class Options
    {
        private string _username;
        private string _password;

        public string Username {
            get { return _username; }
            set { _username = value;}
        }

        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }
    }
}

As I mentioned before, the code I'm using to try to serialize/deserialize this object is located in an assembly that doesn't know about the Options type at compilation time (since it loads P.dll dynamically at runtime). Nevertheless, I managed to serialize the type correctly, by using this code:

如前所述,我用于序列化/反序列化此对象的代码位于编译时不知道选项类型的程序集中(因为它加载了P)。在运行时动态dll)。尽管如此,我还是通过使用以下代码成功地将类型序列化为:

//Assembly = A.exe (doesn't know about P.dll at compile time)
object value = GetOptions() //the actual type returned by this method is EDFPlugin.Plugin1.Options !!
XmlSerializer valueSerializer = new XmlSerializer(value.GetType());
valueSerializer.Serialize(writer, value);

basically, as you can see, by calling GetType() I can get around the issue of not having knowledge of the Options type at compilation time, everything works fine.

基本上,如您所见,通过调用GetType(),我可以解决在编译时不了解选项类型的问题,一切都很好。

The problem arises when I try to deserialize:

当我试图反序列化时,问题就出现了:

//Assembly = A.exe (doesn't know about P.dll at compile time)
XmlSerializer valueSerializer = new XmlSerializer(typeof(object)); //have to use object, as I don't know the type in question...
object value = valueSerializer.Deserialize(reader); //throws exception

Since I don't know the type in question beforehand, I basically cannot properly setup the XmlSerializer. Using a generic object, as shown in the code above, generates an exception:

由于我事先不知道问题的类型,所以基本上无法正确地设置XmlSerializer。如上面代码所示,使用通用对象会产生一个异常:

"<Options xmlns='EDFPlugin.Plugin1'> was not expected."

How can I solve this?

我怎么解决这个问题?

1 个解决方案

#1


3  

A.exe (doesn't know about P.dll at compile time)

一个。exe(不知道P。dll在编译时)

So if A.exe knows it at runtime, you shoud be able do load dynamically EDFPlugin.Plugin1

所以如果一个。exe在运行时知道它,您应该能够动态地加载EDFPlugin.Plugin1

How about :

如何:

XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options")); 
object value = valueSerializer.Deserialize(reader);

But what if I don't know that typename either?

但是,如果我也不知道这个名字呢?

It recommend to put a custom interface to distinguish option class to other class, then you'll be able to filter dynamically and load it with XmlSerializer.

它建议使用自定义接口将选项类与其他类区分开来,然后您就可以动态地过滤并使用XmlSerializer加载它。

public interface IAmPlugin
{

}

public class Options: IAmPlugin
{
      ......
}

Then :

然后:

Assembly assembly = ... // Your Assemblie which contains plugin 

// XmlSerializer needs all possible types to Deserialize an interface 
var possibleTypes = assembly.GetTypes().Where(t => t.IsClass && t.IsAssignableFrom(typeof(IAmPlugin))).ToArray(); 

XmlSerializer serializer = new XmlSerializer(typeof(IAmPlugin), possibleTypes);
object value = valueSerializer.Deserialize(reader);

This assumes you have a empty public constructors on Options class.

这假定在Options类上有一个空的公共构造函数。

Why an interface instead of an Attribute? Because XmlSerializer handles only multiple interface type.

为什么是接口而不是属性?因为XmlSerializer只处理多个接口类型。

#1


3  

A.exe (doesn't know about P.dll at compile time)

一个。exe(不知道P。dll在编译时)

So if A.exe knows it at runtime, you shoud be able do load dynamically EDFPlugin.Plugin1

所以如果一个。exe在运行时知道它,您应该能够动态地加载EDFPlugin.Plugin1

How about :

如何:

XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options")); 
object value = valueSerializer.Deserialize(reader);

But what if I don't know that typename either?

但是,如果我也不知道这个名字呢?

It recommend to put a custom interface to distinguish option class to other class, then you'll be able to filter dynamically and load it with XmlSerializer.

它建议使用自定义接口将选项类与其他类区分开来,然后您就可以动态地过滤并使用XmlSerializer加载它。

public interface IAmPlugin
{

}

public class Options: IAmPlugin
{
      ......
}

Then :

然后:

Assembly assembly = ... // Your Assemblie which contains plugin 

// XmlSerializer needs all possible types to Deserialize an interface 
var possibleTypes = assembly.GetTypes().Where(t => t.IsClass && t.IsAssignableFrom(typeof(IAmPlugin))).ToArray(); 

XmlSerializer serializer = new XmlSerializer(typeof(IAmPlugin), possibleTypes);
object value = valueSerializer.Deserialize(reader);

This assumes you have a empty public constructors on Options class.

这假定在Options类上有一个空的公共构造函数。

Why an interface instead of an Attribute? Because XmlSerializer handles only multiple interface type.

为什么是接口而不是属性?因为XmlSerializer只处理多个接口类型。