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.
精彩评论