【问题标题】:c# xml missing element in nested classesc# xml 嵌套类中缺少元素
【发布时间】:2018-11-16 06:17:46
【问题描述】:

我有一个小问题困扰了我好几天。我正在为虚拟赛车联盟编写一种管理工具。 我想将我的所有数据保存到一个 xml 文件中,以便可以轻松地从多方访问。 但是,由于 xml-serializer 的限制,id 必须公开我的所有类。为此我写了一个界面 我想通过它将我原来的管理对象(具有所有功能)转换为包含用于 xml 序列化的对象的原始数据。

为了能够跟踪谁创建/更改了某些相关内容,每个相关人员都需要保存一个“ChangeNotification”字段。 为此,我使用这些字段创建了一个基类,并且我的容器类是从该基类派生的。

现在问题来了:如果我只序列化其中的一部分,一切都可以正常工作。但是一旦我序列化一个包含另一个从同一基础派生的对象的对象, 我的“CreateChangeNotification”只会出现在顶部对象中。

我不明白它为什么这样做,因为它显然有两个实例保存在对象中,同时持有不同的值。

抱歉,sn-p 代码太长了,但这是我重新创建问题所需要的,而且似乎每次使用这种结构都会发生。

[Serializable()]
public class DataManagerXmlContainer<DataContainerType> : IDataManagerContainer
{
    [XmlElement("Created")]
    public ChangeNotificationXmlContainer created;

    [XmlIgnore()]
    public IChangeNotificationDataContainer Created { get => created; set => created = new ChangeNotificationXmlContainer(value); }

    //[XmlElement("Changed")]
    //public ChangeNotificationXmlContainer changed;

    //[XmlIgnore()]
    //public IChangeNotificationDataContainer LastChange { get => changed; set => changed = new ChangeNotificationXmlContainer(value); }

    public DataManagerXmlContainer() { }
}

[Serializable()]
public class ReviewDataXmlContainer : DataManagerXmlContainer<IReviewDataContainer>, IReviewDataContainer
{
    [XmlArray("CommentList")]
    [XmlArrayItem("Comment")]
    public List<ReviewCommentXmlContainer> comments = new List<ReviewCommentXmlContainer>();
    [XmlIgnore()]
    public ICollection<IReviewCommentDataContainer> Comments
    {
        get => comments.Cast<IReviewCommentDataContainer>().ToList();
        set => comments = value.ToList().ConvertAll(x => new ReviewCommentXmlContainer(x));
    }

    public ReviewDataXmlContainer() { }

    public ReviewDataXmlContainer(string authorID)
    {
        created = new ChangeNotificationXmlContainer(authorID, DateTime.Now);
    }

    public void AddComment(IReviewCommentDataContainer comment)
    {
        comments.Add(new ReviewCommentXmlContainer(comment));
    }
}

[Serializable()]
public class ReviewCommentXmlContainer : DataManagerXmlContainer<IReviewCommentDataContainer>, IReviewCommentDataContainer
{
    [XmlAttribute("author_id")]
    public string AuthorAdminID { get; set; }
    public string Text { get; set; }

    public ReviewCommentXmlContainer() { }

    public ReviewCommentXmlContainer(string authorID, string text)
    {
        created = new ChangeNotificationXmlContainer(authorID, DateTime.Now);
        AuthorAdminID = authorID;
        Text = text;
    }

    public ReviewCommentXmlContainer(IReviewCommentDataContainer dataContainer)
    {
        AuthorAdminID = dataContainer.AuthorAdminID;
        Text = dataContainer.Text;
    }
}

[Serializable()]
public class ChangeNotificationXmlContainer : IChangeNotificationDataContainer
{
    [XmlAttribute("author_id")]
    public string AuthorID { get; set; }

    [XmlAttribute("time")]
    public DateTime Time { get; set; }

    public ChangeNotificationXmlContainer() { }

    public ChangeNotificationXmlContainer(string id, DateTime time)
    {
        AuthorID = id;
        Time = time;
    }

    public ChangeNotificationXmlContainer(IChangeNotificationDataContainer dataContainer)
    {
        AuthorID = dataContainer.AuthorID;
        Time = dataContainer.Time;
    }
}

public interface IChangeNotificationDataContainer
{
    string AuthorID { get; set; }
    DateTime Time { get; set; }
}

public interface IDataManagerContainer
{
    IChangeNotificationDataContainer Created { get; set; }
}

public interface IReviewDataContainer : IDataManagerContainer
{
    ICollection<IReviewCommentDataContainer> Comments { get; set; }
    void AddComment(IReviewCommentDataContainer comment);
}

public interface IReviewCommentDataContainer : IDataManagerContainer
{
    string AuthorAdminID { get; set; }
    string Text { get; set; }
}

以及程序代码:

class Program
{
    static void Main(string[] args)
    {
        IReviewCommentDataContainer comment = new ReviewCommentXmlContainer("12345", "This is a test");
        Task.Delay(1000).Wait();
        ReviewDataXmlContainer review = new ReviewDataXmlContainer("23456");
        review.AddComment(comment);


        XmlSerializer serializer = new XmlSerializer(typeof(ReviewDataXmlContainer));
        TextWriter writer = new StreamWriter("Test.xml");
        serializer.Serialize(writer, review);

        //Task.Delay(-1).Wait();
    }
}

这就是我的 xml 的样子:

<?xml version="1.0" encoding="utf-8"?>
<ReviewDataXmlContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Created author_id="23456" time="2018-11-16T06:56:16.5425819+01:00" />
    <CommentList>
        <Comment author_id="12345">
            <Text>This is a test</Text>
        </Comment>
    </CommentList>
</ReviewDataXmlContainer>

正如你所见,评论的创建元素只是缺失了。

【问题讨论】:

  • 这实际上并没有回答您的问题,但我不得不问 - 您是否考虑过其他持久性选项?如果你喜欢基于文件的为什么不sqlite.org/onefile.html。你最终可能会保留你的头发......
  • 谢谢。我会调查一下。但是,该项目的主要目标是学习如何使用接口和序列化等。
  • 当序列化一个继承另一个类的类时,你需要一个包含:[XmlInclude(type)]
  • 谢谢,我稍后再试。
  • @jdweng:在研究 [xmlinclude] 时,我只发现了用于序列化派生类型的用法。在这种情况下,我希望它正确序列化它应该已经知道的基本类型的成员。在这种情况下我将如何使用 [xmlinclude]?

标签: c# xml serialization


【解决方案1】:

我发现了问题。通过接口添加评论对象时,changenotification 不会被带走并且会丢失。 在我完整的代码中,这个问题被掩盖了一些,因为我使用反射来自动设置所有属性。 但是,我只查看主要接口类型,而不是所有已实现的接口类型。 我更改了代码,现在它工作正常。 不过感谢您的支持。

【讨论】:

    猜你喜欢
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多