Вопрос

Привет, предположим, что эти 2 метода:

private List<IObjectProvider> GetProviderForType(Type type)
        {
            List<IObjectProvider> returnValue = new List<IObjectProvider>();

            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
            {
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))
                {
                    returnValue.Add(provider.Value);
                }
            }
            return returnValue;
        }

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
        {
            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))

                    yield return provider.Value;              
        }

Какой из них быстрее?Когда я смотрю на первый метод, то вижу, что под List выделена память, что на мой взгляд не нужно.А IEnumerable Мне этот метод кажется более быстрым.

Например, предположим, что вы звоните

int a = GetProviderForType(myType).Count;
int b = GetProviderForType1(myType).Count();

Теперь еще один вопрос: есть ли разница в производительности между этими двумя устройствами, указанными выше?

Что вы думаете?

Это было полезно?

Решение

В этом конкретном случае использование формы IEnumerable < T > будет более эффективным, поскольку вам only нужно знать количество. Нет смысла хранить данные, изменять размеры буферов и т. Д., Если вам это не нужно.

Если по какой-либо причине вам потребуется снова использовать результаты, форма List < T > будет более эффективной.

Обратите внимание, что метод расширения Count () и свойство Count будут эффективными для List < T > как реализации < code> Count () проверяет, реализует ли целевая последовательность ICollection < T > и использует свойство Count , если это так.

Другой вариант, который должен быть даже более эффективным (хотя бы только), - вызвать перегрузку Count , которая принимает делегата:

private int GetProviderCount(Type type)
{
  return _objectProviders.Count(provider =>
      (provider.Key.IsAssignableFrom(type) 
       || type.IsAssignableFrom(provider.Key))
      && provider.Value.SupportsType(type));
}

Это позволит избежать дополнительного уровня косвенных указаний, возникающих в связи с предложениями Where и Select .

(Как говорит Марк, для небольших объемов данных различия в производительности, вероятно, будут в любом случае незначительными.)

Другие советы

Точный ответ на подобные вопросы может варьироваться в зависимости от множества факторов и может меняться по мере развития CLR. Единственный способ убедиться в этом - это измерить его и иметь в виду, что если разница невелика по сравнению с операцией, в которой это будет отображаться, то вам следует выбрать наиболее читаемый и понятный способ ее записи.

И на этой заметке вы также можете попробовать:

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
{
    return _objectProviders.Where(provider => 
                  provider.Key.IsAssignableFrom(type) ||
                  type.IsAssignableFrom(provider.Key)) &&
                  provider.Value.SupportsType(type))
                           .Select(p => p.Value);
}

Вы также можете проявить большую гибкость, возвращая IEnumerable < T > , а затем используя метод расширения ToList , если вы хотите " снимок " результаты в список. Это позволит избежать повторной оценки кода для генерации списка, если вам придется проверять его несколько раз.

Важной частью этого вопроса является "насколько велики данные"? Сколько строк ...

Для небольших объемов данных список подойдет - потребуется незначительное время, чтобы выделить достаточно большой список, и он не будет много раз изменяться (нет, если вы можете сказать, насколько большим он должен быть заранее).

Однако это не масштабируется до огромных объемов данных; кажется маловероятным, что ваш провайдер поддерживает тысячи интерфейсов, поэтому я бы не сказал, что необходимо перейти на эту модель - но это не сильно повредит.

Конечно, вы также можете использовать LINQ:

return from provider in _objectProviders
       where provider.Key.IsAssignableFrom(type) ...
       select provider.Value;

Это также отложенный подход yield под прикрытием ...

Основное различие между IEnumerable и IList:

IEнумерабле:Реализует Movenext, сбросьте, получайте текущие методы и возвращает тип ienumerator для итерации через записи.

IList:Предоставляет интерфейс IEnumerable, а также коллекцию неуниверсальных объектов, доступ к которым можно получить через индекс, поэтому IEnumerable+ICollection(манипуляция данными) и add,remove,Insert(по определенному индексу) являются полезными методами, реализованными IList.

Посмотрев на ваш код, по моему мнению, IEnumerable более эффективен, но возвращаемый список также полезен, если вы хотите выполнить некоторые манипуляции с данными, и если вы просто хотите перебирать данные, тогда IEnumerable предпочтительнее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top