c# - 添加属性后如何从 XML 反序列化?
问题描述
我有一个类似的课程:
public class Script
{
public string Name { get; set; }
public string HomeKey { get; set; } = "";
}
它将像这样从 XML 文件反序列化:
<Script>
<Name>ScriptName</Name>
<HomeKey>KeyText</HomeKey>
</Script>
使用以下代码可以正常工作:
[Test]
public void DeserializeScriptTest()
{
// Arrange
var contents = Helpers.LoadEmbeddedResourceFileContents("test.xml");
var serializer = new XmlSerializer(typeof(Script));
Script s;
// Act
using (var reader = new StringReader(contents))
{
s = (Script)serializer.Deserialize(reader);
}
// Assert
Assert.AreEqual("KeyText", s.HomeKey);
}
而且我有很多使用这些文件的客户端代码,并且将来会继续使用它们。
现在我的 XML 文件略有变化,如下所示:
<Script>
<Name>ScriptName</Name>
<HomeKey KeyId="12345">KeyText</HomeKey>
</Script>
我的老客户应该仍然能够反序列化这个文件,因为旧的 HomeKey 仍然在同一个地方。新客户端也需要反序列化属性值。所以我创建了一个新类:
public class ScriptV2 : Script
{
public new HomeKeyV2 HomeKey { get; set; } = new HomeKeyV2();
}
public class HomeKeyV2
{
[XmlAttribute]
public int KeyId { get; set; }
[XmlText]
public string Value { get; set; } = "";
}
旧代码适用于新文件就好了。但是,新代码不起作用。
当我运行这个:
[Test]
public void DeserializeScriptV2Test()
{
// Arrange
var contents = Helpers.LoadEmbeddedResourceFileContents("test.xml");
var serializer = new XmlSerializer(typeof(ScriptV2), new XmlRootAttribute("Script")); // <-- Exception here
ScriptV2 s;
// Act
using (var reader = new StringReader(contents))
{
s = (ScriptV2)serializer.Deserialize(reader);
}
// Assert
Assert.AreEqual("KeyText", s.HomeKey.Value);
}
我在标记线上遇到异常:
System.InvalidOperationException
HResult=0x80131509
Message=There was an error reflecting type 'Project.Classes.ScriptV2'.
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, String defaultNamespace, String location, Evidence evidence)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, XmlRootAttribute root)
at Project.Tests.DeserializeScriptV2Test() in foobarTests.cs:line 12
Inner Exception 1:
InvalidOperationException: There was an error reflecting property 'HomeKey'.
Inner Exception 2:
InvalidOperationException: Member ScriptV2.HomeKey of type Project.Classes.HomeKeyV2 hides base class member Script.HomeKey of type System.String. Use XmlElementAttribute or XmlAttributeAttribute to specify a new name.
如何更改 ScriptV2 以使其与 xml 文件的新结构一起使用?我无法更改 Script.cs 或将更新的代码部署到旧客户端。他们都可以正常使用更改后的 XML 文件。
解决方案
这对我有用
[XmlRoot(ElementName = "HomeKey")]
public class HomeKey
{
[XmlAttribute(AttributeName = "KeyId")]
public string KeyId { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlRoot(ElementName = "Script")]
public class ScriptV2
{
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
[XmlElement(ElementName = "HomeKey")]
public HomeKey HomeKey { get; set; }
}
用法
var contents = "<Script>\r\n <Name>ScriptName</Name>\r\n <HomeKey KeyId=\"12345\">KeyText</HomeKey>\r\n</Script>";
var serializer = new XmlSerializer(typeof(ScriptV2), new XmlRootAttribute("Script"));
using (var reader = new StringReader(contents))
{
var s = (ScriptV2)serializer.Deserialize(reader);
}
推荐阅读
- javascript - JS如何返回所有同名的人
- haskell - :sprint 和 `seq` 一起 - 缺少评估?
- haskell - 哈斯克尔。这个函数如何捕获负数作为参数?
- firebase - 每次打开页面时都会加载 AngularFire 列表
- java - 使用套接字进行 Java 登录
- python - open() 中的整数文件描述符“0”
- python - 使用主 .f90 模块调用特定 .f 文件运行 f2py 时出现问题?(unknown_subroutine?)
- reactjs - 对 node_module 的更改未反映 reactjs
- python - 扫描字符串文字错误时被 EOL 弄糊涂了
- android - 我有旋转 Android 应用程序,我在退出时遇到问题