XML序列化基类而不知道派生类
本文关键字:派生 不知道 序列化 基类 XML | 更新日期: 2023-09-27 18:26:52
我知道,如果传入的类型与创建序列化程序时的类型不匹配,XmlSerializer
将引发异常。
我的问题是:是否可以在不知道派生类型的情况下序列化基类型?考虑这个场景:
以下类位于顶级域中,几乎没有依赖项:
public class Serializer
{
private static string Serialize(Base baseData)
{
var serializer = new XmlSerializer(typeof(Base));
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
serializer.Serialize(writer, baseData);
}
return sb.ToString();
}
private static string Deserialize(...) { ... }
}
public class Base
{
public string Name { get; set; }
}
以下派生类在UI组件、组合等方面有额外的依赖项(稍后会详细介绍):
[Export(typeof(IMyComponent))]
public class Derived : Base, IMyComponent, INotifyPropertyChanged
{
public new string Name
{
get { return base.Name; }
set
{
base.Name = value;
NotifyPropertyChanged("Name");
}
}
}
如果我这样调用序列化程序:
Base myData = new Derived();
myData.Name = "Foo bar";
Serializer.Serialize(myData);
它抛出了一个异常,因为我传入了一个Derived
,即使参数和序列化程序被显式设置为Base
。我只想序列化Base
,我不在乎Derived
中有什么。
我的目标是创建具有UI的派生类,但仅序列化基类。原因是我正在一个单独的程序集中反序列化XML,该程序集不能包含.NET框架之外的其他依赖项将序列化程序和基对象重新创建/复制到此隔离程序集中,以便命名空间和类型匹配,以便在进行反序列化时,正确地反序列化类型。但我不能包含Derived
的副本,因为它依赖于UI、MEF、其他第三方库等。
那么,即使我传入了派生类,我如何才能强制序列化程序序列化基类呢?同样,我不在乎我是否丢失了Derived
中的信息,我关心的只是Base
。
由于您只希望序列化Base属性,因此必须创建Base的实例并从派生类型映射属性。序列化程序被编程为智能的,有时在您的情况下过于智能。
查看AutoMapper或手动执行。
public class Serializer
{
private static string Serialize(Base baseData)
{
var mappedBase = new Base();
// Do mapping
mappedBase.Foo = baseData.Foo;
var serializer = new XmlSerializer(typeof(Base));
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
serializer.Serialize(writer, mappedBase);
}
return sb.ToString();
}
private static string Deserialize(...) { ... }
}
一种可能的解决方案是:
public class Serializer
{
public static string Serialize(Base baseData)
{
var baseType = baseData.GetType().BaseType;
var baseTypeFieldInfo = baseType.GetProperties();
var newBaseInstance = new Base();
var newBaseInstanceType = newBaseInstance.GetType();
//ONLY gets public properties but could be applied to fields
var newBaseTypeFieldInfo = newBaseInstanceType.GetProperties();
foreach (var bt in baseTypeFieldInfo)
{
foreach (var nbt in newBaseTypeFieldInfo)
{
if (nbt.Name == bt.Name)
{
nbt.SetValue(newBaseInstance, bt.GetValue(baseData, null), null);
}
}
}
var serializer = new XmlSerializer(typeof(Base));
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
serializer.Serialize(writer, newBaseInstance);
}
return sb.ToString();
}
}
public class Base
{
public string Name { get; set; }
}
public class Derived : Base
{
public string AnotherName { get; set; }
public new string Name
{
get { return base.Name; }
set { base.Name = value; }
}
}