C # List vs IEnumerable pergunta desempenho
-
06-07-2019 - |
Pergunta
Hi supõem estes 2 métodos:
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;
}
Qual deles é mais rápido? Quando eu olho para o primeiro método, vejo que a memória é alocada para a lista, o que na minha opinião não é necessário. O IEnumerable método parece ser mais rápido para mim.
Por exemplo, suponha que você chamar
int a = GetProviderForType(myType).Count;
int b = GetProviderForType1(myType).Count();
Agora, outra questão é, existe uma diferença de desempenho entre estes 2 acima?
O que você acha?
Solução
Neste caso particular, utilizando o formulário IEnumerable<T>
será mais eficiente, porque você única necessidade de saber a contagem. Não há nenhum ponto em armazenar os dados, redimensionamento buffers etc, se você não precisa.
Se você precisava usar os resultados novamente por qualquer motivo, a forma List<T>
seria mais eficiente.
Note que tanto o método de extensão Count()
ea propriedade Count
será eficiente para List<T>
como a implementação de cheques Count()
para ver se os instrumentos de sequências-alvo ICollection<T>
e usa a propriedade Count
se assim for.
Outra opção que deve ser mesmo mais eficiente (embora só agora) seria chamar a sobrecarga de Count
que leva um delegado:
private int GetProviderCount(Type type)
{
return _objectProviders.Count(provider =>
(provider.Key.IsAssignableFrom(type)
|| type.IsAssignableFrom(provider.Key))
&& provider.Value.SupportsType(type));
}
Isso vai evitar o nível extra de indireções incorridos pelas cláusulas Where
e Select
.
(Como Marc diz, para pequenas quantidades de dados as diferenças de desempenho provavelmente será de qualquer maneira insignificante.)
Outras dicas
A resposta precisa a perguntas como esta pode variar dependendo de uma série de fatores, e pode mudar ainda mais com a evolução CLR. A única maneira de ter certeza é medi-la -. E ter em mente que, se a diferença é pequena em comparação com a operação deste aparecerão na, então você deve escolher a forma mais legível, de fácil manutenção de escrevê-lo
E nessa nota, que você pode também querer tentar:
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);
}
Você também pode dar-se muita flexibilidade, retornando IEnumerable<T>
e, em seguida, usando o método de extensão ToList
se você quiser "instantâneo" os resultados em uma lista. Isso irá evitar a avaliação repetida do código para gerar a lista, se você precisa examiná-lo várias vezes.
Uma parte importante desta questão é "quão grande são os dados"? Quantas linhas ...
Para pequenas quantidades de dados, a lista é muito bem - isso vai levar tempo insignificante para alocar uma lista grande o suficiente, e que não irá redimensionar muitas vezes (nenhum, se você pode dizer como é grande para ser com antecedência) <. / p>
No entanto, isso não escala a grandes volumes de dados; parece improvável que o seu provedor suporta milhares de interfaces de, então eu não diria que é necessário para ir para este modelo -. mas não irá prejudicar imensamente
É claro, você pode usar LINQ, também:
return from provider in _objectProviders
where provider.Key.IsAssignableFrom(type) ...
select provider.Value;
Esta é também a abordagem yield
diferido sob o cobre ...
A principal diferença entre IEnumerable e IList:
IEnumerable: Implementos MoveNext, Reset, Get Métodos atual e retorna um tipo de IEnumerator para iterar Através Records.
IList: expõe a interface IEnumerable, assim como também é uma coleção de objetos não genéricos que pode acessado através índice para IEnumerable + ICollection (manipulação de dados) e adicionar, remover, Insert (pelo índice específico) são úteis métodos implementados por IList.
Depois de olhar para o seu código em minha opinião IEnumerable é mais eficiente, mas a lista de retornar também é útil se você quiser fazer alguma manipulação com os dados e se você quiser apenas para percorrer os dados, em seguida, IEnumerable é preferível.