Сведения о вопросе

Gentleman

13:32, 27th August, 2020

Теги

c#   .net   vb.net   generics   collections    

Что это лучший способ, чтобы выполнить итерации через строго типизированный общего списка?

Просмотров: 500   Ответов: 7

Как лучше всего перебирать строго типизированный универсальный список в C#.NET и VB.NET?



  Сведения об ответе

park

21:06, 1st October, 2020

Для C#:

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

Ответ для VB.NET из фиолетового Ant :

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


  Сведения об ответе

park

00:05, 20th August, 2020

С любой универсальной реализацией IEnumerable лучший способ-это:

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

Однако есть важное исключение. IEnumerable включает в себя накладные расходы в размере Current() и MoveNext(), в которые фактически компилируется цикл foreach.

Когда у вас есть простой массив структур:

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

Это быстрее.


Обновление

После обсуждения с @Steven Sudit (см. комментарии) я думаю, что мой первоначальный совет может быть устаревшим или ошибочным, поэтому я провел несколько тестов:

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

Итак, я запустил это в релизе со всеми оптимизациями:

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

А потом отлаживать без оптимизаций:

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

Таким образом, он выглядит довольно последовательным, for быстрее, чем foreach , и массивы быстрее, чем универсальные списки.

Однако это происходит через 100 000 000 итераций, и разница составляет около .4 секунды между самыми быстрыми и самыми медленными методами. Если вы не делаете массивные циклы критической производительности, то просто не стоит беспокоиться об этом.


  Сведения об ответе

lesha

07:29, 3rd August, 2020

Для VB.NET:

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


  Сведения об ответе

dump

07:16, 25th August, 2020

C#

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

Анонимные делегаты в настоящее время не реализованы в VB.Net, но и C#, и VB.Net должны иметь возможность выполнять лямбды:

C#

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

VB.Net

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

Как отметил Грауэн Волк, вышеупомянутый VB не будет компилироваться, так как lambda не возвращает значения. Обычный цикл ForEach, как предполагали другие, вероятно, самый простой на данный момент, но, как обычно, требуется блок кода, чтобы сделать то, что может сделать C# в одной строке.


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

Допустим, у вас есть список относительных путей url, которые вы хотите сделать абсолютными:

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

    return paths.ForEach(formatter);
}

Таким образом, вы можете вызвать функцию таким образом:

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

Даю вам "http://myhost.com/about", "http://myhost.com/contact" и т.д. Очевидно, что есть лучшие способы достичь этого в этом конкретном примере, я просто пытаюсь продемонстрировать основной принцип.


  Сведения об ответе

park

06:03, 3rd August, 2020

Не зная внутренней реализации списка, я думаю, что в целом лучшим способом итерации по нему будет цикл foreach. Поскольку foreach использует IEnumerator для обхода списка, то сам список определяет, как переходить от объекта к объекту.

Если бы внутренняя реализация была, скажем, связанным списком, то простой цикл for был бы намного медленнее, чем foreach.

Есть ли в этом смысл?


  Сведения об ответе

PAGE

02:11, 4th August, 2020

Это зависит от вашего приложения:

  • для цикла, если эффективность является приоритетом
  • foreach цикл или ForEach метод, в зависимости от того, что передает ваше намерение более четко


  Сведения об ответе

SSESION

15:30, 10th August, 2020

Возможно, я что-то упускаю, но повторение общего списка должно быть довольно простым, если вы используете мои примеры ниже. Класс List<> реализует интерфейсы IList и IEnumerable, так что вы можете легко перебирать их практически любым способом.

Наиболее эффективным способом было бы использовать цикл for:

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

Вы также можете использовать цикл foreach:

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться