假设我在名为ClassLibrary1
的模块中有这个简单的类:
[DataContract]
public class Class1
{
[DataMember]
private DataTable _data;
public void SetData(string key, object value)
{
_data = new DataTable("SomeName");
_data.Columns.Add("Key", typeof(String));
_data.Columns.Add("Value", value.GetType());
_data.Rows.Add(key, value);
}
}
在一个名为ClassLibrary2
的单独模块中,我有以下类:
[DataContract]
public class Configuration
{
[DataMember]
private Class1 _obj;
public Configuration()
{
_obj = new Class1();
_obj.SetData("Key", MyEnum.Value2);
}
}
此外,模块ClassLibrary2
定义了一个名为MyEnum
的枚举,它未标记为公共,即它在模块内部(并在上面的代码中使用,如您所见)。
现在,在我的主模块中,我不想依赖ClassLibrary2
,而是需要在运行时动态加载它。也就是说,我使用Assembly.LoadFrom
,然后找到我需要使用的类型(在我的简单示例中,我只搜索名为“Configuration”的类型),并使用Activator.CreateInstance
创建实例。然后我像这样序列化实例:
var ser = new DataContractSerializer(config.GetType());
var outstream = new FileStream("c:\\test.xml", FileMode.Create);
ser.WriteObject(outstream, config);
outstream.Close();
到目前为止,一切都有效。但是,当我尝试将其反序列化时:
var instream = new FileStream("c:\\test.xml", FileMode.Open);
var conf = ser.ReadObject(instream);
我收到ArgumentException
,并显示消息“列需要有效的数据类型”。我发现,如果我要么
String key; Object value
但在我的实际应用中,这些选项都不是很理想。第一个选项将在模块之间创建一个不应相互依赖的强耦合。第二个选项是可能的,但是有点工作(我已经在整个类中使用了DataTable很多地方,并且最近才发现我必须进行序列化),第三个选项也有点混乱。
还有其他方法可以让它发挥作用吗?我还尝试将MyEnum添加到序列化程序的已知类型列表中,通过DataContractSerializer
构造函数和[KnownType(typeof(MyEnum))]
类声明前面附加Configuration
,但这没有帮助
答案 0 :(得分:0)
底层代码无法找到自动写在test.xml文件中的ClassLibrary2程序集全名。它需要一些帮助。
如果您先挂钩AppDomain.AssemblyResolve Event之前的反序列化,可以解决此问题,如下所示:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;
...
var instream = new FileStream("test.xml", FileMode.Open);
var conf = ser.ReadObject(instream);
...
private static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name == "ClassLibrary2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null") // adapt to your needs of course
return Assembly.LoadFrom(@"mypath\ClassLibrary2.dll");
return null; // don't know for this one
}