如何使用DataContractSerializer反序列化一个包含枚举值的数据表的对象?

本文关键字:包含 枚举 数据表 对象 一个 DataContractSerializer 何使用 反序列化 | 更新日期: 2023-09-27 18:18:01

假设我在一个名为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的enum,它没有被标记为public,也就是说,它是模块内部的(并且在上面的代码中使用,如您所见)。

现在,在我的主模块中,我不想依赖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,带有消息"Column需要一个有效的DataType"。我发现,如果执行以下命令

,则不会发生这种情况
  • 在主模块中定义MyEnum
  • 将DataTable替换为简单的String key; Object value
  • 使用其他东西代替enum MyEnum(例如字符串)

但是这些选项在我的实际应用程序中都不是很理想。第一个选项将在模块之间创建不应该相互依赖的强耦合。第二种选择是可能的,但需要做一些工作(我已经在整个类的许多地方使用了DataTable,直到最近才发现我必须进行序列化),第三种选择也有点混乱。

还有其他方法可以让这个工作吗?我还尝试通过DataContractSerializer构造函数和在Configuration类声明之前附加[KnownType(typeof(MyEnum))],将MyEnum添加到序列化器的已知类型列表中,但这没有帮助。

如何使用DataContractSerializer反序列化一个包含枚举值的数据表的对象?

底层代码就是找不到自动写在test.xml文件中的ClassLibrary2程序集全名。它需要一些帮助。

如果你钩子AppDomain,你可以解决这个问题。AssemblyResolve事件先验反序列化,如下所示:
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
}