C#Xml序列化:不能(de)序列化来自另一个程序集的对象

Mas*_*r_T 5 .net c# serialization xml-serialization xmlserializer

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

我正在尝试序列化的类型是这样的:

//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; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如我之前提到的,我用来尝试序列化/反序列化这个对象的代码位于一个程序集中,该程序集Options在编译时不知道类型(因为它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);
Run Code Online (Sandbox Code Playgroud)

基本上,正如你所看到的,通过调用GetType()我可以解决Options在编译时不知道类型的问题,一切正常.

当我尝试反序列化时出现问题:

//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
Run Code Online (Sandbox Code Playgroud)

由于事先我不知道有问题的类型,我基本上无法正确设置XmlSerializer.使用泛型object,如上面的代码所示,生成一个异常:

"<Options xmlns='EDFPlugin.Plugin1'> was not expected."
Run Code Online (Sandbox Code Playgroud)

我怎么解决这个问题?

Per*_*t28 3

A.exe(编译时不知道P.dll)

因此,如果 A.exe 在运行时知道它,您应该能够动态加载EDFPlugin.Plugin1

怎么样 :

XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options")); 
object value = valueSerializer.Deserialize(reader);
Run Code Online (Sandbox Code Playgroud)

但如果我也不知道该类型名称怎么办?

建议放置一个自定义接口来区分选项类和其他类,然后您将能够动态过滤并使用 XmlSerializer 加载它。

public interface IAmPlugin
{

}

public class Options: IAmPlugin
{
      ......
}
Run Code Online (Sandbox Code Playgroud)

然后 :

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);
Run Code Online (Sandbox Code Playgroud)

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

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