C# Xml 序列化:无法(反)序列化来自另一个程序集的对象
C# Xml Serialization: can't (de)serialize an object that comes from another assembly
我正在尝试 XML serialize/deserialize C# 中的对象。问题在于此对象的类型未在与调用序列化的代码相同的程序集中声明。相反,它来自运行时动态加载的程序集,因此调用序列化的代码在编译时是未知的。
我要序列化的类型是这样的:
//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; }
}
}
}
正如我之前提到的,我用来尝试 serialize/deserialize 这个对象的代码位于一个程序集中,该程序集在编译时不知道 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);
基本上,如您所见,通过调用 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
由于我事先不知道所讨论的类型,所以我基本上无法正确设置 XmlSerializer
。使用泛型object
,如上面代码所示,会产生异常:
"<Options xmlns='EDFPlugin.Plugin1'> was not expected."
我该如何解决这个问题?
A.exe (doesn't know about P.dll at compile time)
所以如果 A.exe 在运行时知道它,你应该能够动态加载 EDFPlugin.Plugin1
怎么样:
XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options"));
object value = valueSerializer.Deserialize(reader);
But what if I don't know that typename either?
建议放置一个自定义界面来区分选项 class 和其他 class,然后您将能够动态过滤并使用 XmlSerializer 加载它。
public interface IAmPlugin
{
}
public class Options: IAmPlugin
{
......
}
然后:
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);
这假设您在选项 class 上有一个空的 public 构造函数。
为什么是接口而不是属性?
因为 XmlSerializer 只处理多种接口类型。
我正在尝试 XML serialize/deserialize C# 中的对象。问题在于此对象的类型未在与调用序列化的代码相同的程序集中声明。相反,它来自运行时动态加载的程序集,因此调用序列化的代码在编译时是未知的。
我要序列化的类型是这样的:
//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; }
}
}
}
正如我之前提到的,我用来尝试 serialize/deserialize 这个对象的代码位于一个程序集中,该程序集在编译时不知道 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);
基本上,如您所见,通过调用 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
由于我事先不知道所讨论的类型,所以我基本上无法正确设置 XmlSerializer
。使用泛型object
,如上面代码所示,会产生异常:
"<Options xmlns='EDFPlugin.Plugin1'> was not expected."
我该如何解决这个问题?
A.exe (doesn't know about P.dll at compile time)
所以如果 A.exe 在运行时知道它,你应该能够动态加载 EDFPlugin.Plugin1
怎么样:
XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options"));
object value = valueSerializer.Deserialize(reader);
But what if I don't know that typename either?
建议放置一个自定义界面来区分选项 class 和其他 class,然后您将能够动态过滤并使用 XmlSerializer 加载它。
public interface IAmPlugin
{
}
public class Options: IAmPlugin
{
......
}
然后:
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);
这假设您在选项 class 上有一个空的 public 构造函数。
为什么是接口而不是属性? 因为 XmlSerializer 只处理多种接口类型。