【问题标题】:How to deserialize from XML after adding an attribute?添加属性后如何从 XML 反序列化?
【发布时间】:2019-10-01 02:38:03
【问题描述】:

我有一个类似的课程:

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 文件。

【问题讨论】:

    标签: c# xml serialization


    【解决方案1】:

    这对我有用

    [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);
    }
    

    【讨论】:

    • 谢谢。这与我所做的足够接近,我会将其标记为已接受。我的大问题是在 ScriptV2 中继承 Script。我只是放弃了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2015-10-24
    相关资源
    最近更新 更多