Удаление элемента из свойства списка в классе

В C# System.Xml.Serialization есть сериализованные XML-данные.

Есть корневой класс, описывающий корневой элемент. Он содержит поля типа List, описанные в классах-потомках (например, Movie).

Я могу десериализовать свой 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 => m.Title == "To be removed: The Godfather" && m.Year == "1974"); cfg.Movies.Remove(toRemove);

Sani Singh Huttunen 17.04.2018 18:08

Это не «xml-класс». Это обычный класс, у которого есть атрибуты сериализации.

15ee8f99-57ff-4f92-890c-b56153 17.04.2018 18:15

Чем отличается этот запрос от вчерашнего? : stackoverflow.com/questions/49867071/…

jdweng 17.04.2018 20:17

@jdweng, это совершенно разные вопросы, у них только схожие xml данные. Первый касается вообще фильтрации xml-узлов, а этот относится конкретно к работе с XmlArray и List. Спасибо.

Vladimir 17.04.2018 21:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
102
2

Ответы 2

Когда вы создаете новый объект, его ссылки еще нет в списке. Вам нужно найти в списке элемент, который вы хотите удалить, а затем удалить его, используя результат поиска.

Что-то вроде:

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")? Можно ли это по-другому описать?

Vladimir 17.04.2018 18:16

Это запрос Linq, который выбирает ровно один элемент в списке. Если элемента нет или есть несколько элементов, соответствующих критериям, возвращается значение по умолчанию (часто null). Критерий состоит в том, что Title и Year должны совпадать для каждого объекта m.

Sani Singh Huttunen 17.04.2018 18:20

Я получаю исключение, если в списке нет подходящего элемента .. Есть ли способ справиться с этим без try-catch?

Vladimir 18.04.2018 11:11

У вас не должно быть никаких исключений. У вас должен получиться null.

Sani Singh Huttunen 18.04.2018 17:01

Вы пытаетесь удалить новый фильм, а не тот, который десериализовали.

Вы должны сначала найти фильм в своем списке, а затем удалить его.

Заменять

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") - как это работает? Есть ли способ написать то же самое без "=>"?

Vladimir 17.04.2018 18:22

"x => x.Title = = " Newly added: Pulp Fiction "- это инструкция предиката, в основном она гласит: найдите мне вхождение" x "в моем списке фильмов, где x.Title равно" Newly added: Pulp Fiction " ". Это реализовано в LINQ feautre C#. Вот руководство, чтобы вы могли понять его основы tutorialspoint.com/linq/linq_overview.htm Также почему вы не хотите использовать этот синтаксис?

Marc 17.04.2018 18:30

Спасибо. Я предпочитаю использовать то, что хорошо понимаю, и LINQ пока для меня не совсем понятная тема. Поэтому я просто хотел знать - это как синтаксический сахар, или в данном случае у него нет альтернативы?

Vladimir 17.04.2018 18:45

Вы можете начать с перехода к списку фильмов, и если один из них имеет в качестве названия искомое значение, сохраните его в переменной. После этого удалите из списка переменную, содержащую вхождение

Marc 18.04.2018 14:43

Другие вопросы по теме