[英]XML serialize base class without knowing derived class
I know that an XmlSerializer
will throw an exception if the passed in type does not match the type from when the serializer was created. 我知道,如果传入的类型与创建序列化器时的类型不匹配,则
XmlSerializer
将引发异常。
My question is: Is it possible to serialize a base type without knowing the derived type? 我的问题是:是否可以在不知道派生类型的情况下序列化基本类型? Consider this scenario:
考虑这种情况:
The following classes are in a top-level domain and have few or no dependencies : 以下类位于顶级域中,几乎没有依赖项 :
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; }
}
The following derived class has additional dependencies on things like UI components, composition, etc. (more on this later): 以下派生类对UI组件,组成等有更多依赖关系 (稍后会对此进行更多介绍):
[Export(typeof(IMyComponent))]
public class Derived : Base, IMyComponent, INotifyPropertyChanged
{
public new string Name
{
get { return base.Name; }
set
{
base.Name = value;
NotifyPropertyChanged("Name");
}
}
}
If I invoke the serializer like this: 如果我这样调用序列化器:
Base myData = new Derived();
myData.Name = "Foo bar";
Serializer.Serialize(myData);
It throws an exception because I passed in a Derived
, even though the parameters and serializer are explicitly set to Base
. 因为我传入了
Derived
,所以它引发了异常,即使参数和序列化程序已显式设置为Base
。 All I want is to serialize Base
, I don't care about whatever is in Derived
. 我只想序列化
Base
,我不在乎Derived
任何内容。
My goal here is to create the derived class with a UI, but only serialize the base class . 我的目标是使用UI创建派生类,但仅序列化基类 。 The reason is that I am deserializing the XML in a separate assembly that must not contain additional dependencies beyond the .NET framework.
原因是我在一个单独的程序集中反序列化XML,该程序集不得包含.NET框架之外的其他依赖项。 The serializer and base objects are recreated/copied into this isolated assembly so that the namespaces and types will match, so that when deserialization occurs, the types will be deserialized correctly.
将序列化程序和基础对象重新创建/复制到此隔离的程序集中,以便名称空间和类型匹配,以便在进行反序列化时,将正确地反序列化类型。 But I can't include a copy of
Derived
because it has dependencies on UI, MEF, other third party libraries, etc. 但是我不能包含
Derived
的副本,因为它依赖于UI,MEF,其他第三方库等。
So, how can I force the serializer to serialize the base class even if I pass in a derived class? 因此,即使传递了派生类,如何强制序列化程序对基类进行序列化? Again, I don't care if I lose the information in
Derived
, all I am concerned about is Base
. 同样,我不在乎是否会丢失
Derived
的信息,我所关心的只是Base
。
One possible solution would be: 一种可能的解决方案是:
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; }
}
}
Since you are looking to only serialize the Base properties, you have to create an instance of Base and map the properties from the derived type. 由于您只想序列化Base属性,因此您必须创建Base实例并从派生类型映射属性。 Serializers are programmed to be smart, sometimes too smart in your case.
序列化器被编程为很聪明,有时就您而言太聪明了。
Look into AutoMapper or just do it manually. 查看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(...) { ... }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.