c# IEnumerable привязан к изменениям XDocument

#c# #xml #list #linq #ienumerable

Вопрос:

У меня есть XML-файл следующего вида:

 <products>
  <product id="1" name="USB Flash Memory 2 GB" />
  <product id="2" name="USB Flash Memory 8 GB" />
  <product id="3" name="Wireless Multi Media Keyboard" />
</products>
 

Я XDocument читал файл и сохранял результат запроса в переменной типа IEnumerable<Product> .

Если я добавил новый элемент в XDocument переменную, она обновляется автоматически, поэтому я подумал, что есть какая-то ошибка, поэтому я попробовал это с List<Product> переменной типа, и это сработало (т. Е. Добавление элемента в XDocument автоматическое обновление без этого ввода).

Итак, мой вопрос в том, почему IEnumerable это связано с XDocument изменениями, в то время List как это не так ?

Полный Код:

 namespace IEnumerableTest
{
    public class Product
    {
        public int ID { get; set; }
        public string ProductName { get; set; }
    }
}


namespace IEnumerableTest
{
    public partial class Form1 : Form
    {
        static string path = @"Products.xml";
        XDocument xDoc = XDocument.Load(path);
        IEnumerable<Product> productsEnum;
        List<Product> productsList;

        public Form1()
        {
            InitializeComponent();

            productsEnum =
                from p in xDoc.Descendants("product")
                select new Product
                {
                    ID = int.Parse(p.Attribute("id").Value),
                    ProductName = p.Attribute("name").Value
                };

            productsList =
                (from p in xDoc.Descendants("product")
                 select new Product
                 {
                     ID = int.Parse(p.Attribute("id").Value),
                     ProductName = p.Attribute("name").Value
                 }).ToList();
        }
        
        void BindDataGridView()
        {
            dataGridViewEnum.DataSource = productsEnum.ToList();
            dataGridViewList.DataSource = productsList;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            BindDataGridView();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            XElement newProduct =
                new XElement("product",
                new XAttribute("id", 4),
                new XAttribute("name", "Wireless USB Optical Mouse"));

            xDoc.Root.Add(newProduct);

            BindDataGridView();
        }
    }
}
 

Результат выглядит так:

введите описание изображения здесь

Комментарии:

1. И IEnumerable это похоже на обещание данных, так что только тогда, когда вы зацикливаетесь на них, то есть когда запрос Linq, который у вас здесь, действительно выполняется.

2. ToList создает копию. IEnumarable использует исходные ссылки.

3. @imsmn Нет, это плохое описание.

4. @DavidG Не стесняйтесь улучшать его, всегда рад описать вещи немного лучше в будущем.

5. @imsmn я уже сделал это в своем комментарии. ToList заставляет запрос выполняться немедленно.

Ответ №1:

An IEnumerable -это как обещание данных, поэтому только когда вы зацикливаетесь на нем (или используете на нем что-то вроде a ToList ), то есть когда запрос Linq, который у вас здесь, фактически выполняется. Рассмотрим следующий код:

 void Main()
{
    IEnumerable<int> numbers = Enumerable.Range(1, 5).Select(x => DoubleNumber(x));

    Console.WriteLine($"There are {numbers.Count()} numbers that were doubled");
    Console.WriteLine($"There are {numbers.Count()} numbers that were doubled");
}

public int DoubleNumber(int value)
{
    Console.WriteLine($"Doubling the number {value}");
    return value * 2;
}
 

Вывод из этого на самом деле:

 Doubling the number 1
Doubling the number 2
Doubling the number 3
Doubling the number 4
Doubling the number 5
There are 5 numbers that were doubled
Doubling the number 1
Doubling the number 2
Doubling the number 3
Doubling the number 4
Doubling the number 5
There are 5 numbers that were doubled
 

Обратите внимание, как вся коллекция чисел была рассчитана дважды. Однако, если вы добавите .ToList() в конец первой строки, это создаст все числа в памяти только один раз и выдаст вам этот вывод:

 Doubling the number 1
Doubling the number 2
Doubling the number 3
Doubling the number 4
Doubling the number 5
There are 5 numbers that were doubled
There are 5 numbers that were doubled
 

Комментарии:

1. Ладно, я понял. Когда я изменил XDocument и вызвал productsEnum его, он был обновлен, потому что запрос был выполнен снова, но на этот раз с XDocument обновленным новым элементом.