【问题标题】:Removing element from list property in class从类中的列表属性中删除元素
【发布时间】:2018-04-17 16:05:32
【问题描述】:

在 C# System.Xml.Serialization 中有一个 XML 数据序列化。

有一个描述根元素的根类。它包含在后代类(如电影)中描述的 List 类型的文件。

我可以将我的 XML 文档反序列化为一个类,并简单地使用 List.Add 或 List.Insert 在列表中添加一个新元素:

cfg.Movies.Insert(0, new Movie("Newly added: Pulp Fiction", "1994"));

但是反向操作不起作用:

cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));

所以问题是如何从 xml 类列表中删除一个元素?

样本在这里:https://dotnetfiddle.net/WqCNoD

using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Xml.Serialization;

public class Program
{
public static void Main()
{

    string xmlString =
        @"<favorites>
                <movies>
                    <movie title=""To be removed: The Godfather"" year=""1974"" />
                    <movie title=""The Terminator"" year=""1984"" />
                    <movie title=""Dark Knight"" year=""2008"" />
                </movies>

                <books>
                    <book title = ""1984"" author=""George Orwell"" />
                    <book title = ""Robinson Crusoe"" author=""Daniel Defoe "" />
                    <book title = ""Frankenstein"" author=""Mary Shelly"" />
                </books>

                <music>
                    <artist title = ""Beatles"" genre=""rock"" />
                    <artist title = ""Queen"" genre=""rock"" />
                    <artist title = ""Metallica"" rock=""heavy metal"" />
                </music>
            </favorites>";

    XDocument xdoc = XDocument.Parse(xmlString);

    var xdocData = xdoc.ToString();

    //DeSerialization
    XmlSerializer serializer = new XmlSerializer(typeof(Favorites));
    using (StringReader reader = new StringReader(xdoc.ToString()))
    {
        Favorites cfg = (Favorites) serializer.Deserialize(reader);


        // Add & remove element
        cfg.Movies.Insert(0, new Movie("Newly added: Pulp Fiction", "1994"));
        cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));


        //Serialization
        XmlSerializer serializer2 = new XmlSerializer(cfg.GetType());

        using (StringWriter writer = new StringWriter())
        {
            serializer2.Serialize(writer, cfg);
            Console.WriteLine(writer.ToString());

        }

    }
}



[XmlRoot(ElementName = "favorites", DataType = "string", IsNullable = true)]
public class Favorites
{
    //public string Name { get; set; }

    [XmlArray("movies")]
    [XmlArrayItem("movie")]
    public List<Movie> Movies { get; set; }

    public Favorites()
    {
        Movies = new List<Movie>();
    }
}


public class Movie
{
    [XmlAttribute("title")]
    public string Title { get; set; }
    [XmlAttribute("year")]
    public string Year { get; set; }

    public Movie() { }

    public Movie(string title, string year)
    {
        Title = title;
        Year = year;
    }
  }
}

【问题讨论】:

  • 当你创建一个新对象时,它的引用还没有在列表中。您需要在列表中搜索要删除的项目,然后使用搜索结果将其删除。比如:var toRemove = cfg.Movies.Single(m =&gt; m.Title == "To be removed: The Godfather" &amp;&amp; m.Year == "1974"); cfg.Movies.Remove(toRemove);
  • 它不是一个“xml 类”。它只是一个恰好有序列化属性的常规类。
  • 这个请求和昨天的请求有什么区别? :stackoverflow.com/questions/49867071/…
  • @jdweng,这是完全不同的问题,它们只有相似的 xml 数据。第一个与过滤 xml 节点有关,而这一个专门与 XmlArray 和 List 的操作有关。谢谢。

标签: c# xml linq


【解决方案1】:

当您创建一个新对象时,它的引用还没有在列表中。您需要在列表中搜索要删除的项目,然后使用搜索结果将其删除。

类似:

var movieToRemove = cfg.Movies.SingleOrDefault(m => m.Title == "To be removed: The Godfather" && m.Year == "1974");
if (moveiToRemove != null)
  cfg.Movies.Remove(movieToRemove);

【讨论】:

  • 您能否解释一下这里发生了什么 - cfg.Movies.SingleOrDefault(m => m.Title == "待删除:教父" && m.Year == "1974") ?可以用其他方式描述吗?
  • 这是一个 Linq 查询,它只选择列表中的一项。如果没有项目或有多个项目与条件匹配,则返回默认值(通常为 null)。标准是TitleYear 必须与每个对象m 匹配。
  • 如果列表中没有匹配的元素,我会得到异常。有没有办法在没有 try-catch 的情况下处理这个问题?
  • 你不应该得到任何异常。你应该得到null
【解决方案2】:

您正在尝试删除一部新电影,而不是您反序列化的电影。

您必须先在列表中找到该电影,然后再将其删除。

替换

cfg.Movies.Remove(new Movie("To be removed: The Godfather", "1974"));

cfg.Movies.Remove(cfg.Movies.Find(x => x.Title == "Newly added: Pulp Fiction"));

【讨论】:

  • 这里缺少知识:( cfg.Movies.Find(x => x.Title == "Newly added: Pulp Fiction") - 它是如何工作的?有没有办法编写相同的代码没有“=>”?
  • "x => x.Title == "Newly added: Pulp Fiction" 是一个谓词指令,它基本上说:让我在我的电影列表中出现 x.Title 的 "x"等于“新添加:低俗小说”。这是由 C# 的 LINQ 功能实现的。这里有一个教程,以便您了解它的基础 tutorialspoint.com/linq/linq_overview.htm 还有你为什么不想使用这个语法?
  • 谢谢。我更喜欢使用我理解好的东西,而 LINQ 目前对我来说还不是完全清楚的话题。所以我只是想知道——它是像语法糖一样,还是在这种情况下别无选择?
  • 您可以首先循环到您的电影列表,如果其中一部电影的标题具有所寻找的值,则将其存储在一个变量中。之后继续从列表中删除包含该事件的变量
猜你喜欢
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 2020-09-28
  • 2017-03-05
相关资源
最近更新 更多