c# IEnumerable<object> 绑定到 XDocument 更改

c# IEnumerable<object> is bound to XDocument changes

我有一个 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();
        }
    }
}

结果是这样的:

IEnumerable 就像数据的承诺,所以只有当你遍历它(或在其上使用类似 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