开发者

Dreadful performance of MoveNext inside class implementing IEnumerable<T>

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 fr开发者_如何学JAVAamework 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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜