Pergunta

Qual é a melhor maneira de iterar por meio de uma lista genérica fortemente tipada em C#.NET e VB.NET?

Foi útil?

Solução

Para C#:

foreach(ObjectType objectItem in objectTypeList)
{
    // ...do some stuff
}

Resposta para VB.NET de Formiga Roxa:

For Each objectItem as ObjectType in objectTypeList
    'Do some stuff '
Next

Outras dicas

Com qualquer implementação genérica de IEnumerable, a melhor maneira é:

//C#
foreach( var item in listVariable) {
    //do stuff
}

Há, no entanto, uma exceção importante.IEnumerable envolve uma sobrecarga de Current() e MoveNext() que é onde o loop foreach é realmente compilado.

Quando você tem um array simples de estruturas:

//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
     int item = valueTypeArray[i];
     //do stuff
}

É mais rápido.


Atualizar

Após uma discussão com @Steven Sudit (ver comentários), acho que meu conselho original pode estar desatualizado ou errado, então fiz alguns testes:

// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();

// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
    int inLoop = item;
}
Console.WriteLine("list  foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theList[i];
}
Console.WriteLine("list  for    : " + sw.Elapsed.ToString());

// now run the same tests, but with an array
var theArray = theList.ToArray();

sw.Reset();
sw.Start();

foreach (var item in theArray)
{
    int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theArray[i];
}
Console.WriteLine("array for    : " + sw.Elapsed.ToString());

Console.ReadKey();

Então, executei isso no lançamento com todas as otimizações:

list  foreach: 00:00:00.5137506
list  for    : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for    : 00:00:00.0954890

E então depure sem otimizações:

list  foreach: 00:00:01.1289015
list  for    : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for    : 00:00:00.4913245

Portanto, parece bastante consistente, for é mais rápido que foreach e matrizes são mais rápidas que listas genéricas.

No entanto, isso ocorre em 100 milhões de iterações e a diferença é de cerca de 0,4 segundo entre os métodos mais rápidos e mais lentos.A menos que você esteja fazendo loops críticos de desempenho massivos, não vale a pena se preocupar.

Para VB.NET:

For Each tmpObject as ObjectType in ObjectTypeList
    'Do some stuff '
Next

C#

myList<string>().ForEach(
    delegate(string name)
    {
        Console.WriteLine(name);
    });

Delegados anônimos não estão atualmente implementados em VB.Net, mas tanto C# quanto VB.Net devem ser capazes de fazer lambdas:

C#

myList<string>().ForEach(name => Console.WriteLine(name));

VB.Net

myList(Of String)().ForEach(Function(name) Console.WriteLine(name))

Como Grauenwolf apontou, o VB acima não será compilado, pois o lambda não retorna um valor.Um loop ForEach normal, como outros sugeriram, é provavelmente o mais fácil por enquanto, mas, como sempre, é necessário um bloco de código para fazer o que o C# pode fazer em uma linha.


Aqui está um exemplo banal de por que isso pode ser útil:isso lhe dá a capacidade de passar a lógica do loop de outro escopo que não onde o IEnumerable existe, então você nem precisa expô-lo se não quiser.

Digamos que você tenha uma lista de caminhos de URL relativos que deseja tornar absolutos:

public IEnumerable<String> Paths(Func<String> formatter) {
    List<String> paths = new List<String>()
    {
        "/about", "/contact", "/services"
    };

    return paths.ForEach(formatter);
}

Então você poderia chamar a função desta forma:

var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);

Dando-lhe "http://myhost.com/about", "http://myhost.com/contact" etc.Obviamente existem maneiras melhores de fazer isso neste exemplo específico, estou apenas tentando demonstrar o princípio básico.

Sem conhecer a implementação interna de uma lista, acho que geralmente a melhor maneira de iterá-la seria um loop foreach.Como foreach usa um IEnumerator para percorrer a lista, cabe à própria lista determinar como passar de um objeto para outro.

Se a implementação interna fosse, digamos, uma lista vinculada, então um loop for simples seria um pouco mais lento que um foreach.

Isso faz sentido?

Depende da sua aplicação:

  • for loop, se a eficiência for uma prioridade
  • loop foreach ou método ForEach, o que comunicar sua intenção com mais clareza

Posso estar faltando alguma coisa, mas iterar uma lista genérica deve ser bastante simples se você usar meus exemplos abaixo.A classe List<> implementa as interfaces IList e IEnumerable para que você possa iterá-las facilmente da maneira que desejar.

A maneira mais eficiente seria usar um loop for:

for(int i = 0; i < genericList.Count; ++i) 
{
     // Loop body
}

Você também pode optar por usar um loop foreach:

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top