2010-12-09 4 views
0

Ich habe eine Wrapper-Klasse, die in einer MVC-Anwendung verwendet wird, die die Elemente in einer Auflistung durchläuft und überprüft, ob der aktuelle Benutzer die Berechtigung zum Zugriff auf dieses Element hat es für die Anzeige. Zum größten Teil funktioniert es wie ein Zauber. Für einen bestimmten Objekttyp läuft es jedoch wie ein absoluter Hund und ich kann nicht herausfinden warum.Schreckliche Leistung von MoveNext innerhalb der Klasse, die IEnumerable implementiert <T>

Klassen Die Schnittstelle werden wie folgt geschrieben:

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

Nun meine erste Frage ist mein Verständnis überprüfen, was hier vor sich geht. Ich bin wahrscheinlich falsch, aber mein Verständnis ist, dass, wenn ich versuche, eine foreach-Schleife gegen eine Sammlung von Typ-Objekten zu verwenden nie System.Collections.IEnumerable.GetEnumerator() - sicherlich, dass Code nie getroffen wird?

Das Problem liegt, wenn ich diesen Wrapper für Protokolldateieinträge verwenden, die über Entitätsframework in einer LogEntryViewDaya-Klasse bereitgestellt werden. Wenn der Code innerhalb von GetEnumerator auf die foreach-Schleife trifft, hält er für volle 6-8 Sekunden an, obwohl nur 20 Elemente in der Enumeration vorhanden sind!

Hier ist der Code für 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; } } 
} 

Soweit ich sagen kann, es in Instanziieren diese Klassen keine nennenswerte Leistung ist - setzen Sie einen Haltepunkt im Konstruktor und F5ing durch scheint glatt wie nichts.

Warum also ist eine Sammlung dieser bestimmten Objekte so langsam zu durchlaufen? Ich habe keine Ahnung: Vorschläge dankbar geschätzt.

Antwort

2

Sie haben uns nicht gezeigt, wie die Klasse gefüllt wird. Meine Schätzung ist, dass die Zeit auf Datenbankabfragen geht - insbesondere abhängig davon, was abgerufen wird, ist es nur möglich, dass es eine Abfrage gibt, um die skelettierten Entitäten zu erhalten, und dann eine Abfrage für von UserCanEdit und UserCanView. Das scheint unwahrscheinlich (ich hätte erwartet, dass der Eintrag diese Eigenschaften bei der ersten Abfrage enthält), aber das ist nur möglich.

Beobachten Sie im Grunde, wie es mit Ihrer Datenbank interagiert.

Ich schlage vor, Sie versuchen, eine Konsole App zu schreiben, die die gleiche Klasse verwendet, so dass Sie damit umgehen können, Timing-Logs usw. leichter hinzufügen als Sie von einer Webanwendung können.

EDIT: Abgesehen von allem anderen in den Kommentaren usw., gibt es einen Grund, warum Sie dies nicht als Teil einer LINQ-Abfrage tun? Zum Beispiel:

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

Ich schätze es wahrscheinlich nicht ganz so einfach sein, wie UserCanEdit auf dem aktuellen Benutzer usw. abhängen wird - aber es soll wohl als eine Datenbankabfrage durchgeführt werden, anstatt client- Seite.

+0

Okay, werde hier meine Unwissenheit zeigen, aber ich hatte angenommen, dass die Klasse bevölkert war, als ihr Konstruktor aufgerufen wurde? Das passiert, bevor es jemals in die foreach Schleife kommt und scheint mit einer befriedigenden Geschwindigkeit aufzutreten. –

+0

@Matt: Nun, Sie haben in einem IEnumerable übergeben, aber das könnte faul ausgewertet werden. Insbesondere, wenn Sie ein IQueryable übergeben, übergeben Sie die * Abfrage * und nicht die Ergebnisse der Auswertung dieser Abfrage.Abgesehen von allem anderen könnten Sie Ihren Konstruktor so ändern, dass er 'ToList()' aufruft und diese Liste speichert, was die Ausführung der Abfrage erzwingt. Grundsätzlich können wir hier nicht genug Code sehen, um zu wissen, was vor sich geht. –

+0

Was brauchen Sie mehr? –

Verwandte Themen