You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中为何IEnumerable随XDocument变更自动更新而List不会

问题描述

现有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>类型存储查询结果后则不会同步更新,询问二者差异的原因。

完整测试代码

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();
        }
    }
}

运行效果

运行效果图


解答

这个差异的核心原因是LINQ的延迟执行(惰性求值)特性:

  • 对于IEnumerable<Product>类型的productsEnum:你在构造函数中给它赋值时,仅仅是存储了LINQ查询的定义逻辑,并没有立刻遍历XDocument的节点生成Product对象。只有当你实际枚举这个IEnumerable的时候(也就是BindDataGridView方法中调用productsEnum.ToList()的时机),才会真正执行查询逻辑,从当前的XDocument中读取所有product节点生成对应实例。所以你给XDocument添加新节点后,下次执行查询自然能拿到最新的节点数据,看起来就像是变量自动更新了。
  • 对于List<Product>类型的productsList:你在构造函数中调用了ToList()方法,相当于强制立刻执行了LINQ查询,将当时XDocument中存在的product节点全部转换为Product实例,存入了List的内存空间中。此时这个List已经和原XDocument完全脱离关联,后续你修改XDocument的内容不会影响已经生成的List中的元素,自然就不会同步更新。

如果不需要IEnumerable随XDocument变更同步更新,只需要在给IEnumerable变量赋值时追加ToList()方法,提前执行查询缓存结果即可。


内容的提问来源于stack exchange,提问作者Taher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 12:15:01