简体   繁体   English

C# XmlSerializer 反序列化抽象 class 不知道具体 class

[英]C# XmlSerializer de-serialize abstract class without knowing concrete class

I would like to deserialize xml where the root class is an Abstract class but the root node in the xml has a value of the XML root attribute in the concrete class. The key is to do this without specifying the concrete class to deserialize in the XmlSerializer constructor. I would like to deserialize xml where the root class is an Abstract class but the root node in the xml has a value of the XML root attribute in the concrete class. The key is to do this without specifying the concrete class to deserialize in the XmlSerializer构造函数。

Example:例子:

MessageType.cs MessageType.cs

[Serializable]
[XmlInclude(typeof(Entity))]
public abstract class MessageType
{
}

Entity.cs实体.cs

[Serializable]
[XmlRoot("Entity", IsNullable = false)]
public class Entity : MessageType
{
    private string data;

    public string Data
    {
        get { return data; }
        set { data = value; }
    }
}

Program.cs程序.cs

var entity = new Entity
{
    Data = "test"
};

var xs = new XmlSerializer(typeof(Entity));

using var stream = new System.IO.StringWriter();

xs.Serialize(stream, entity);
var xml = stream.ToString();

using var stringReader = new System.IO.StringReader(xml);

xs = new XmlSerializer(typeof(MessageType));
var obj = serializer.Deserialize(stringReader);

This code results in此代码导致

Unhandled exception. System.InvalidOperationException: There is an error in XML document (2, 2).
 ---> System.InvalidOperationException: <Entity xmlns=''> was not expected.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMessageType.Read4_MessageType()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)

The xml produced by the serialization in the code above looks like:上面代码中序列化产生的 xml 如下所示:

<?xml version="1.0" encoding="utf-16"?>
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Data>test</Data>
</Entity>

Couple Extra Notes:夫妇额外注意事项:

  1. In the real case, the xml message comes from another application that I have 0 control over.在实际情况中,xml 消息来自另一个我无法控制的应用程序。
  2. The c# classes come from an XSD so I'm unable to change those either c# 类来自 XSD,所以我也无法更改它们
  3. There are a lot of concrete class implementations of the MessageType class and with xml deserialization seeming to be a slow process, looping over each possible type and seeing if it can deserialize is not ideal有很多MessageType class 的具体 class 实现和 xml 反序列化似乎是一个缓慢的过程,遍历每种可能的类型并查看它是否可以反序列化并不理想
  4. I know there are a lot of similar questions on stackoverflow but have been unable to find one that answers my exact question我知道在 stackoverflow 上有很多类似的问题,但一直找不到能回答我确切问题的问题
  5. I understand if the received xml looked like我知道如果收到的 xml 看起来像
    <?xml version="1.0" encoding="utf-16"?> <MessageType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Entity"> <Data>test</Data> </MessageType>
    that it would work, but refer to note #1.它会起作用,但请参阅注释 #1。

You can get the name of the root node with the XmlReader.您可以使用 XmlReader 获取根节点的名称。 Then you can get the type by name and create the serializer accordingly.然后您可以通过名称获取类型并相应地创建序列化程序。

using var xmlReader = XmlReader.Create(stream);
xmlReader.MoveToContent();
var rootNodeName = xmlReader.Name;

var implementationType = Type.GetType(rootNodeName);
if (implementationType != null)
{
    var serializer = new XmlSerializer(implementationType);
    var obj = serializer.Deserialize(xmlReader);
}
else
{
    // unknown type
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM