将 XML 反序列化为来自基础 class 的派生对象 c#
Deserialize XML to derived objects from base class c#
我想将 XML 反序列化为派生对象(使用基础 class):
第一个XML:
<?xml version="1.0"?>
<root>
<elementOne>101</elementOne>
<elementTwo>10</elementTwo>
</root>
第二个XML:
<?xml version="1.0"?>
<root>
<elementOne>101</elementOne>
<elementTwo>10</elementTwo>
<elementThree>10</elementThree>
</root>
我有以下基地class:
[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}
以下派生 classes:
public class DerivedOneClass: ResponseBase
{
[XmlElementAttribute("elementOne")]
public string ElementOne {get; set;}
[XmlElementAttribute("elementTwo")]
public string ElementTwo {get; set;}
}
public class DerivedTwoClass: ResponseBase
{
[XmlElementAttribute("elementOne")]
public string ElementOne {get; set;}
[XmlElementAttribute("elementTwo")]
public string ElementTwo {get; set;}
[XmlElementAttribute("elementThree")]
public string ElementThree {get; set;}
}
但是无法使用base反序列化class,代码如下:
(T)(new XmlSerializer(typeof(T))).Deserialize(reader);
您需要让序列化程序知道派生的 类。
你有两个选择:
属性
[XmlInclude(typeof(DerivedOneClass))]
[XmlInclude(typeof(DerivedTwoClass))]
[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}
直接传
(T)(new XmlSerializer(typeof(T),
new[]{typeof(DerivedOneClass),typeof(DerivedTwoClass)}
)).Deserialize(reader);
序列化数据时,XmlSerializer
会自动为每个项目添加一个xsi:Type
属性。在你的例子中,序列化器不知道你想反序列化两个 类 中的哪一个,所以如果你不是生成 XML 的那个,你可能需要手动解析 XML 用 XmlDocument
或类似的东西。
另一种方法(如果您想保留 XmlSerializer
)是在解析之前手动确定类型。
private static void AddTypeDefinition(XmlDocument document)
{
const string xsiNamespaceUri = "http://www.w3.org/2001/XMLSchema-instance";
XmlNode node = document.SelectSingleNode("root");
if (node == null) return;
string type = "DerivedOneClass";
XmlNodeList nodes = node.SelectNodes("//elementThree");
if(nodes != null && nodes.Count > 0)
type = "DerivedTwoClass";
var typeAttribute = node.Attributes["type", xsiNamespaceUri];
if (typeAttribute != null) continue;
XmlAttribute attribute = document.CreateAttribute("xsi", "type", xsiNamespaceUri);
attribute.Value = type;
node.Attributes.Append(attribute);
}
可以这样使用:
XmlSerializer serializer = new XmlSerializer(typeof(ResponseBase));
XmlDocument document = new XmlDocument();
document.Load(stream);
AddTypeDefinition(document);
XmlReader reader = new XmlNodeReader(originalDocument);
ResponseBase result = serializer.Deserialize(reader) as ResponseBase;
我想将 XML 反序列化为派生对象(使用基础 class):
第一个XML:
<?xml version="1.0"?>
<root>
<elementOne>101</elementOne>
<elementTwo>10</elementTwo>
</root>
第二个XML:
<?xml version="1.0"?>
<root>
<elementOne>101</elementOne>
<elementTwo>10</elementTwo>
<elementThree>10</elementThree>
</root>
我有以下基地class:
[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}
以下派生 classes:
public class DerivedOneClass: ResponseBase
{
[XmlElementAttribute("elementOne")]
public string ElementOne {get; set;}
[XmlElementAttribute("elementTwo")]
public string ElementTwo {get; set;}
}
public class DerivedTwoClass: ResponseBase
{
[XmlElementAttribute("elementOne")]
public string ElementOne {get; set;}
[XmlElementAttribute("elementTwo")]
public string ElementTwo {get; set;}
[XmlElementAttribute("elementThree")]
public string ElementThree {get; set;}
}
但是无法使用base反序列化class,代码如下:
(T)(new XmlSerializer(typeof(T))).Deserialize(reader);
您需要让序列化程序知道派生的 类。 你有两个选择:
属性
[XmlInclude(typeof(DerivedOneClass))]
[XmlInclude(typeof(DerivedTwoClass))]
[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}
直接传
(T)(new XmlSerializer(typeof(T),
new[]{typeof(DerivedOneClass),typeof(DerivedTwoClass)}
)).Deserialize(reader);
序列化数据时,XmlSerializer
会自动为每个项目添加一个xsi:Type
属性。在你的例子中,序列化器不知道你想反序列化两个 类 中的哪一个,所以如果你不是生成 XML 的那个,你可能需要手动解析 XML 用 XmlDocument
或类似的东西。
另一种方法(如果您想保留 XmlSerializer
)是在解析之前手动确定类型。
private static void AddTypeDefinition(XmlDocument document)
{
const string xsiNamespaceUri = "http://www.w3.org/2001/XMLSchema-instance";
XmlNode node = document.SelectSingleNode("root");
if (node == null) return;
string type = "DerivedOneClass";
XmlNodeList nodes = node.SelectNodes("//elementThree");
if(nodes != null && nodes.Count > 0)
type = "DerivedTwoClass";
var typeAttribute = node.Attributes["type", xsiNamespaceUri];
if (typeAttribute != null) continue;
XmlAttribute attribute = document.CreateAttribute("xsi", "type", xsiNamespaceUri);
attribute.Value = type;
node.Attributes.Append(attribute);
}
可以这样使用:
XmlSerializer serializer = new XmlSerializer(typeof(ResponseBase));
XmlDocument document = new XmlDocument();
document.Load(stream);
AddTypeDefinition(document);
XmlReader reader = new XmlNodeReader(originalDocument);
ResponseBase result = serializer.Deserialize(reader) as ResponseBase;