MoveNext 在实现 IEnumerable 的类中表现糟糕

发布于 2024-10-07 00:19:59 字数 2149 浏览 4 评论 0 原文

我有一个在 MVC 应用程序中使用的包装类,该类旨在循环访问集合中的项目,并在返回该项目进行显示之前检查当前用户是否有权访问该项目。在大多数情况下,它就像一个魅力。然而,对于一种特定的对象类型,它运行得像一只绝对的狗,我不明白为什么。

接口类是这样写的:

    private readonly IEnumerable<T> _ViewData;

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T item in _viewData)
        {
            if (item.UserCanEdit || item.UserCanView)
                yield return item;
        }
    }


    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
         return GetEnumerator();
    }

现在我的第一个问题是检查我对这里发生的事情的理解。我可能是错的,但我的理解是,当我尝试对类型对象集合运行 foreach 循环时,它永远不需要使用 System.Collections.IEnumerable.GetEnumerator() - 当然该代码永远不会被命中?

问题在于,当我尝试在日志文件条目上使用此包装器时,日志文件条目是通过 LogEntryViewDaya 类中的实体框架传递的。当代码到达 GetEnumerator 内的 foreach 循环时,它会停止整整 6-8 秒,即使枚举中只有 20 个项目!

这是 LogEntryView 的代码

public class LogEntryViewData:BaseViewData
{
    private LogEntry _entry;
    public LogEntryViewData(LogEntry entry, ICustomerSecurityContext securityContext) : base(securityContext)
    {
        _entry = entry;
    }

    public string Application { get { return _entry.Application; } }
    public string CurrentUser { get { return _entry.CurrentUser; } }
    public string CustomerName { get { return _entry.CustomerName; } }
    public DateTime Date { get { return _entry.Date; } }
    public string Exception { get { return _entry.Exception; } }
    public string HostName { get { return _entry.HostName; } }
    public long Id { get { return _entry.Id; } }
    public string Level { get { return _entry.Level; } }
    public string Message { get { return _entry.Message; } }
    public int? ProcessId { get { return _entry.ProcessId; } }
    public int? ServiceId { get { return _entry.ServiceId; } }
    public string ServiceName { get { return _entry.ServiceName; } }
    public int? TaskId { get { return _entry.TaskId; } }
    public int? TaskName { get { return _entry.TaskName; } }
    public string Thread { get { return _entry.Thread; } }
}

据我所知,实例化这些类没有明显的性能 - 在构造函数中放置一个断点并通过 F5 似乎很顺利。

那么为什么这些特定对象的集合的迭代速度如此之慢呢?我不知道:非常感谢建议。

I've got a wrapper class that's used in an MVC application that is designed to loop through the items in a collection and check that the current user has authorisation to access that item before returning it for display. For the most part it works like a charm. However for one particular object type it runs like an absolute dog and I can't work out why.

The Interface classes are written like this:

    private readonly IEnumerable<T> _ViewData;

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T item in _viewData)
        {
            if (item.UserCanEdit || item.UserCanView)
                yield return item;
        }
    }


    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
         return GetEnumerator();
    }

Now my first question is check my understanding of what's going on here. I'm probably wrong, but my understanding is that when I try and run a foreach loop against a collection of type objects it never needs to use System.Collections.IEnumerable.GetEnumerator() - certainly that code never gets hit?

The problem lies when I try and use this wrapper on log file entries, which are delivered via entity framework in a LogEntryViewDaya class. When the code hits the foreach loop inside GetEnumerator it stop for a full 6-8 seconds, even though there are only 20 items in the enumeration!

Here's the code for LogEntryView

public class LogEntryViewData:BaseViewData
{
    private LogEntry _entry;
    public LogEntryViewData(LogEntry entry, ICustomerSecurityContext securityContext) : base(securityContext)
    {
        _entry = entry;
    }

    public string Application { get { return _entry.Application; } }
    public string CurrentUser { get { return _entry.CurrentUser; } }
    public string CustomerName { get { return _entry.CustomerName; } }
    public DateTime Date { get { return _entry.Date; } }
    public string Exception { get { return _entry.Exception; } }
    public string HostName { get { return _entry.HostName; } }
    public long Id { get { return _entry.Id; } }
    public string Level { get { return _entry.Level; } }
    public string Message { get { return _entry.Message; } }
    public int? ProcessId { get { return _entry.ProcessId; } }
    public int? ServiceId { get { return _entry.ServiceId; } }
    public string ServiceName { get { return _entry.ServiceName; } }
    public int? TaskId { get { return _entry.TaskId; } }
    public int? TaskName { get { return _entry.TaskName; } }
    public string Thread { get { return _entry.Thread; } }
}

As far as I can tell there's no appreciable performance in instantiating these classes - putting a breakpoint in the constructor and F5ing through seems slick as anything.

So why is a collection of these particular objects so slow to iterate through? I have no idea: suggestions gratefully appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

北音执念 2024-10-14 00:19:59

您还没有向我们展示班级是如何填充的。我的猜测是,数据库查询的时间正在流逝 - 特别是,根据所获取的内容,可能有一个查询来获取骨架实体,然后对每个实体进行一个查询 UserCanEditUserCanView。这似乎不太可能(我希望该条目在初始查询中填充这些属性),但只是有可能。

基本上,观察它如何与数据库交互。

我建议你尝试编写一个使用相同类的控制台应用程序,这样你就可以比在网络应用程序中更轻松地使用它、添加计时日志等。

编辑:除了评论等中的其他内容之外,您是否有任何理由不将其作为 LINQ 查询的一部分来执行?例如:

var query = db.LogEntries.Where(x => x.UserCanEdit || x.UserCanView);

我很欣赏它可能不会那么简单,因为 UserCanEdit 将取决于当前用户等 - 但它可能应该作为数据库完成查询而不是客户端。

You haven't shown us how the class is being populated. My guess is that the time is going on database queries - in particular, depending on what's being fetched, it's just possible that there's one query to get the skeletal entities, and then one query for each of UserCanEdit and UserCanView. That seems unlikely (I'd have expected the entry to have those properties populated on the initial query) but just possible.

Basically, watch how it's interacting with your database.

I suggest you try to write a console app which uses the same class, so you can mess around with it, add timing logs etc more easily than you can from a webapp.

EDIT: Aside from everything else in the comments etc, is there any reason you're not doing this as part of a LINQ query? For example:

var query = db.LogEntries.Where(x => x.UserCanEdit || x.UserCanView);

I appreciate it probably won't be quite as simple as that, as UserCanEdit will depend on the current user etc - but it probably should be done as a database query rather than client-side.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文