C# IEnumerable 访问后清空

C# IEnumerable Emptied Once Accessed

我正在建立一个 Umbraco 8 网站并且 运行 遇到了一些奇怪的行为。该项目正在使用.NET 4.7.2。

基本上,我有一个 Event 类型的 IENumerable,这是一个简单的内容列表,我想将其呈现到列表中。但是,每当我对列表(包含项目)执行任何操作时,列表都会立即清空。这包括简单地分配给不同的变量,检查 null 等。

我不认为这是 Umbraco 8 的问题,但为了清楚起见,我目前正在 运行 通过 Surface Controller 并通过在我的视图中调用以下命令来渲染它:

@Html.Action("RenderUpcoming", "Events")

这是控制器:

using Index.Models.Events;
using Index.Models.PublishedContent;
using Papermoon.Umbraco.Kupo.Core.Services.Interfaces;
using System;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Web.Mvc;

namespace Index.Web.Controllers.Surface
{
    public class EventsController : SurfaceController
    {
        private readonly KupoGeneralSettings _kupoGeneralSettings;

        public EventsController(IKupoSettingsService kupoSettingsService)
        {
            _kupoGeneralSettings = kupoSettingsService.GetSettings<KupoGeneralSettings>("kupoGeneralSettings");
        }

        public ActionResult RenderUpcoming()
        {
            UpcomingEventsModel model = new UpcomingEventsModel();

            model.Title = "Upcoming Events";

            model.Events = Umbraco.ContentAtXPath("root/homepage/events/event").Select(x => new Event(x));

            model.Events = model.Events.Where(x => x.StartDate > DateTime.Now).OrderBy(x => x.StartDate).Take(3);

            model.TotalEvents = model.Events.Count();

            model.EventListingLink = _kupoGeneralSettings.EventListingLink;

            return PartialView("~/Views/Partials/Events/UpcomingEvents.cshtml", model);
        }
    }
}

所以在这里,当我调用 model.Events = model.Events.Where(x => x.StartDate > DateTime.Now).OrderBy(x => x.StartDate).Take(3); - 我有结果,然后当我调用 model.TotalEvents = model.Events.Count(); 时,列表 (model.Events) 是空的。

当我分配给另一个变量时,当我调用 model.Events.Any() 时,甚至当我执行 Model.Events != null.

时,也会发生这种情况

展示这件事可能比说出来更容易,所以请看随附的 gif 动图:https://i.imgur.com/rE3VAqe.gif

谢谢,

当然 – 你不知道对象的实际类型,只是知道它是你可以迭代的东西(IEnumerable)。

例如,它可能是一个 returns 无限事物流的生成器(好吧,在这种情况下你知道它不是)。

如果您需要一个具体的集合,您可以使用 .ToList() 将其转换为 List<> 您当然可以迭代多次。

你的IEnumerable来自这个电话:

Umbraco.ContentAtXPath("root/homepage/events/event")

我不知道具体是如何完成的,因为它是 Umbraco 业务,但 IEnuemerable 本身允许 "lazy" 评估。这意味着例如如果您在没有缓冲的情况下从 SQL 数据库中读取,则每次迭代时它都会读取。

根据数据,它可以 return 相同的结果或新的结果(如果数据已更改)。因此,您在 IEnumerable 中得到的内容完全取决于实现细节,因此,如果您重申,您不知道幕后发生了什么(从没什么特别的到新的数据库查询)。

要在 IEnumerable 的来源未知时防止此行为,您可以在查询结束时执行 ToList()

Umbraco.ContentAtXPath("root/homepage/events/event")
   .Select(x => new Event(x))
   .ToList();

将发生的事情是您遍历一次集合并将所有元素添加到列表中。除非您自己执行此操作,否则此列表不会更改。