反序列化相同 class 的替代名称
Deserialize alternative names for the same class
我有一个与以下内容不完全不同的序列化程序:
[Serializable]
public class MSG
{
[XmlAttribute]
public string Name { get; set; } = string.Empty;
[XmlText]
public string Content { get; set; } = string.Empty;
}
public MSG DeserializeMyMsg(string xmlstr)
{
TextReader reader = new StringReader(xmlstr);
var serializer = new XmlSerializer(typeof(MSG));
MSG ret = serializer.Deserialize(reader) as MSG;
return ret;
}
这将成功反序列化以下内容:
<MSG Name="woho">any content</MSG>
偶尔数据可以到达:
<Mg Name="woho">any content</Mg>
如何将 Mg
标记为 MSG
的替代名称?
MSG 是根。固定 Mg 将是长期目标,但也不是一种选择。消息可以用外根进行改造。
您在评论中提到您可以包装 xml。这感觉很像黑客攻击,但这很有效。一般来说,我的建议是不要这样做!
所以您的 xml 将是:
<NewRoot><MSG Name="woho">any content</MSG></NewRoot>
或者
<NewRoot><Mg Name="woho">any content</Mg></NewRoot>
然后定义这些类并反序列化上面的xml:
public class NewRoot
{
[XmlElement("MSG", typeof(MSG))]
[XmlElement("Mg", typeof(Mg))]
public MSG Msg {get;set;}
}
public class Mg : MSG {}
AFAIK,仅修改序列化属性是不可能直接实现的。但是您可以做的是引入另一种具有不同属性的类型,然后调整您的反序列化逻辑以选择合适的序列化程序。
遗留模型:
[XmlRoot("Mg")]
public class MSGLegacyWrapper : MSG { }
反序列化逻辑:
public static MSG DeserializeMyMsg(string xmlstr)
{
using (var reader = new StringReader(xmlstr))
using (var xmlreader = XmlReader.Create(reader))
using (var serializationReader = new StringReader(xmlstr))
{
var serializer = new XmlSerializer(typeof(MSG));
var chosenSerializer = serializer.CanDeserialize(xmlreader)
? serializer
: new XmlSerializer(typeof(MSGLegacyWrapper));
return chosenSerializer.Deserialize(serializationReader) as MSG;
}
}
当然可以进一步优化决策过程。
选项 1
如果您已经对输入进行了预处理,那么您也可以在反序列化为强类型模型之前使用字符串操作(ex regex)规范化根标签名称。
备选方案 2
如果您的架构 simple/stable 足够,您可以放弃基于属性的反序列化并实现您自己的自定义 XmlReader
,它可以处理替代根元素。请参阅文档和示例 from MSDN。
我相信如果性能很重要,那么这是最快的选择。
我有一个与以下内容不完全不同的序列化程序:
[Serializable]
public class MSG
{
[XmlAttribute]
public string Name { get; set; } = string.Empty;
[XmlText]
public string Content { get; set; } = string.Empty;
}
public MSG DeserializeMyMsg(string xmlstr)
{
TextReader reader = new StringReader(xmlstr);
var serializer = new XmlSerializer(typeof(MSG));
MSG ret = serializer.Deserialize(reader) as MSG;
return ret;
}
这将成功反序列化以下内容:
<MSG Name="woho">any content</MSG>
偶尔数据可以到达:
<Mg Name="woho">any content</Mg>
如何将 Mg
标记为 MSG
的替代名称?
MSG 是根。固定 Mg 将是长期目标,但也不是一种选择。消息可以用外根进行改造。
您在评论中提到您可以包装 xml。这感觉很像黑客攻击,但这很有效。一般来说,我的建议是不要这样做!
所以您的 xml 将是:
<NewRoot><MSG Name="woho">any content</MSG></NewRoot>
或者
<NewRoot><Mg Name="woho">any content</Mg></NewRoot>
然后定义这些类并反序列化上面的xml:
public class NewRoot
{
[XmlElement("MSG", typeof(MSG))]
[XmlElement("Mg", typeof(Mg))]
public MSG Msg {get;set;}
}
public class Mg : MSG {}
AFAIK,仅修改序列化属性是不可能直接实现的。但是您可以做的是引入另一种具有不同属性的类型,然后调整您的反序列化逻辑以选择合适的序列化程序。
遗留模型:
[XmlRoot("Mg")]
public class MSGLegacyWrapper : MSG { }
反序列化逻辑:
public static MSG DeserializeMyMsg(string xmlstr)
{
using (var reader = new StringReader(xmlstr))
using (var xmlreader = XmlReader.Create(reader))
using (var serializationReader = new StringReader(xmlstr))
{
var serializer = new XmlSerializer(typeof(MSG));
var chosenSerializer = serializer.CanDeserialize(xmlreader)
? serializer
: new XmlSerializer(typeof(MSGLegacyWrapper));
return chosenSerializer.Deserialize(serializationReader) as MSG;
}
}
当然可以进一步优化决策过程。
选项 1
如果您已经对输入进行了预处理,那么您也可以在反序列化为强类型模型之前使用字符串操作(ex regex)规范化根标签名称。
备选方案 2
如果您的架构 simple/stable 足够,您可以放弃基于属性的反序列化并实现您自己的自定义 XmlReader
,它可以处理替代根元素。请参阅文档和示例 from MSDN。
我相信如果性能很重要,那么这是最快的选择。