Страшная производительность MoveNext внутри класса, реализующего IEnumerable <T> - PullRequest
0 голосов
/ 09 декабря 2010

У меня есть класс-оболочка, который используется в приложении 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. Когда код попадает в цикл foreach внутри GetEnumerator, он останавливается на полные 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 кажется гладкой, как и все.

Так почему же коллекция этих конкретных объектов так медленно перебирает? Понятия не имею: предложения с благодарностью приветствуются.

1 Ответ

2 голосов
/ 09 декабря 2010

Вы не показали нам, как заполняется класс.Моя догадка заключается в том, что время идет на запросы к базе данных - в частности, в зависимости от того, что выбирается, просто возможно, что есть один запрос для получения скелетных сущностей, а затем один запрос для каждого из UserCanEdit и UserCanView.Это кажется маловероятным (я ожидал, что запись будет заполнять эти свойства в начальном запросе), но просто возможно.

По сути, посмотрите, как оно взаимодействует с вашей базой данных.

Я предлагаю вампопробуйте написать консольное приложение, которое использует тот же класс, так что вы можете возиться с ним, добавлять журналы времени и т. д. проще, чем в веб-приложении.

РЕДАКТИРОВАТЬ: Помимо всего прочего в комментариях и т. д.,есть ли причина, по которой вы не делаете это как часть запроса LINQ?Например:

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

Я понимаю, что, вероятно, это будет не так просто, так как UserCanEdit будет зависеть от текущего пользователя и т. Д., Но, вероятно, следует сделатькак запрос к базе данных, а не на стороне клиента.

...