Jak uzyskać indeks bieżącej iteracji pętli foreach?

Czy jest jakaś rzadka konstrukcja języka, z którą nie spotkałem się (jak kilka, których nauczyłem się ostatnio, niektóre na Stack Overflow) w C#, aby uzyskać wartość reprezentującą bieżącą iterację pętli foreach?

Na przykład, obecnie robię coś takiego w zależności od okoliczności:

int i=0;
foreach (Object o in collection)
{
    // ...
    i++;
}
 699
Author: user7116, 2008-09-04

30 answers

{[0] } służy do iteracji nad zbiorami, które implementują IEnumerable. Robi to poprzez wywołanie GetEnumerator na zbiórce, która zwróci Enumerator.

Ten Enumerator ma metodę i właściwość:

  • MoveNext ()
  • Current

Current zwraca obiekt, na którym aktualnie znajduje się Enumerator, MoveNext aktualizuje Current do następnego obiektu.

Oczywiście, pojęcie indeksu jest obce pojęciu wyliczenia i nie da się tego zrobić.

Z tego powodu większość zbiorów może być przemieszczana za pomocą indeksatora i konstrukcji pętli for.

Zdecydowanie wolę używać pętli for w tej sytuacji w porównaniu do śledzenia indeksu za pomocą zmiennej lokalnej.

 448
Author: FlySwat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 14:54:35

Ian Mercer opublikował podobne rozwiązanie na Blog Phila Haacka :

foreach (var item in Model.Select((value, i) => new { i, value }))
{
    var value = item.value;
    var index = item.i;
}

To dostaje element (item.value) i jego indeks (item.i) za pomocą tego przeciążenia LINQ ' a Select:

Drugi parametr funkcji [Inside Select] reprezentuje indeks elementu źródłowego.

new { i, value } tworzy nowy obiekt anonimowy .

 460
Author: bcahill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 11:42:39

Mógłby zrobić coś takiego:

public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}
 101
Author: Brad Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 01:49:28

Nie zgadzam się z komentarzami, że pętla for jest w większości przypadków lepszym wyborem.

foreach jest użytecznym konstruktem i nie jest zastępowany przez pętlę for we wszystkich okolicznościach.

Na przykład, jeśli masz DataReader i pętlę przez wszystkie rekordy za pomocą foreach to automatycznie wywołuje metodę Dispose i zamyka czytnik (który może następnie automatycznie zamknąć połączenie). Jest to zatem bezpieczniejsze, ponieważ zapobiega wyciekom połączenia, nawet jeśli zapomnisz Zamknij czytnik.

(na pewno jest dobrą praktyką, aby zawsze zamykać czytelników, ale kompilator nie złapie tego, jeśli tego nie zrobisz - nie możesz zagwarantować, że zamknąłeś wszystkich czytelników, ale możesz zwiększyć prawdopodobieństwo, że nie wyciekniesz z połączenia poprzez przyzwyczajenie się do używania foreach.)

Mogą być inne przykłady użycia metody Dispose.

 78
Author: mike nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-25 10:07:34

Dosłowna odpowiedź -- Uwaga, wydajność może nie być tak dobra, jak użycie int do śledzenia indeksu. Przynajmniej jest to lepsze niż użycie IndexOf.

Wystarczy użyć przeciążenia indeksowania Select, aby zawinąć każdy element w kolekcji anonimowym obiektem, który zna indeks. Można to zrobić przeciwko wszystkiemu, co implementuje IEnumerable.

System.Collections.IEnumerable collection = Enumerable.Range(100, 10);

foreach (var o in collection.OfType<object>().Select((x, i) => new {x, i}))
{
    Console.WriteLine("{0} {1}", o.i, o.x);
}
 56
Author: Amy B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-27 07:44:42

W końcu C#7 ma przyzwoitą składnię pozwalającą na uzyskanie indeksu wewnątrz pętli foreach (tj. krotek):

foreach (var (item, index) in collection.WithIndex())
{
    Debug.WriteLine($"{index}: {item}");
}

Przydałaby się mała metoda rozszerzenia:

public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)       
   => self.Select((item, index) => (item, index)); 
 48
Author: user1414213562,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-19 16:59:36

Korzystając z odpowiedzi @ FlySwat, wymyśliłem takie rozwiązanie:

//var list = new List<int> { 1, 2, 3, 4, 5, 6 }; // Your sample collection

var listEnumerator = list.GetEnumerator(); // Get enumerator

for (var i = 0; listEnumerator.MoveNext() == true; i++)
{
  int currentItem = listEnumerator.Current; // Get current item.
  //Console.WriteLine("At index {0}, item is {1}", i, currentItem); // Do as you wish with i and  currentItem
}

Otrzymujesz enumerator za pomocą GetEnumerator, a następnie pętlę za pomocą for. Jednak sztuczka polega na tym, aby warunek pętli listEnumerator.MoveNext() == true.

Ponieważ metoda MoveNext enumeratora zwraca true, jeśli istnieje następny element i można do niego uzyskać dostęp, co sprawia, że warunek pętli zatrzymuje pętlę, gdy zabraknie elementów do iteracji.

 32
Author: Gezim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-07 22:49:52

Możesz zawinąć oryginalny enumerator innym, który zawiera informacje o indeksie.

foreach (var item in ForEachHelper.WithIndex(collection))
{
    Console.Write("Index=" + item.Index);
    Console.Write(";Value= " + item.Value);
    Console.Write(";IsLast=" + item.IsLast);
    Console.WriteLine();
}

Oto kod dla klasy ForEachHelper.

public static class ForEachHelper
{
    public sealed class Item<T>
    {
        public int Index { get; set; }
        public T Value { get; set; }
        public bool IsLast { get; set; }
    }

    public static IEnumerable<Item<T>> WithIndex<T>(IEnumerable<T> enumerable)
    {
        Item<T> item = null;
        foreach (T value in enumerable)
        {
            Item<T> next = new Item<T>();
            next.Index = 0;
            next.Value = value;
            next.IsLast = false;
            if (item != null)
            {
                next.Index = item.Index + 1;
                yield return item;
            }
            item = next;
        }
        if (item != null)
        {
            item.IsLast = true;
            yield return item;
        }            
    }
}
 22
Author: Brian Gideon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-23 13:02:41

Oto rozwiązanie, które właśnie wymyśliłem dla tego problemu

Kod Oryginalny:

int index=0;
foreach (var item in enumerable)
{
    blah(item, index); // some code that depends on the index
    index++;
}

Zaktualizowany kod

enumerable.ForEach((item, index) => blah(item, index));

Metoda Rozszerzenia:

    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
    {
        var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
        enumerable.Select((item, i) => 
            {
                action(item, i);
                return unit;
            }).ToList();

        return pSource;
    }
 16
Author: mat3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-31 11:31:41

Nie ma nic złego w używaniu zmiennej counter. W rzeczywistości, czy używasz for, foreach while lub do, zmienna licznika musi być gdzieś zadeklarowana i zwiększona.

Więc użyj tego idiomu, jeśli nie jesteś pewien, czy masz odpowiednio indeksowaną kolekcję:

var i = 0;
foreach (var e in collection) {
   // Do stuff with 'e' and 'i'
   i++;
}

Else użyj tego, jeśli wiesz , że Twoja indeksowalna kolekcja jest O(1) dla dostępu do indeksu (co będzie dla Array i prawdopodobnie dla List<T> (dokumentacja nie mówi), ale nie koniecznie dla innych typów (takich jakLinkedList)):

// Hope the JIT compiler optimises read of the 'Count' property!
for (var i = 0; i < collection.Count; i++) {
   var e = collection[i];
   // Do stuff with 'e' and 'i'
}

Nigdy nie powinno być konieczne "ręczne" działanie IEnumerator poprzez wywołanie MoveNext() i przesłuchiwanie Current - foreach oszczędza ci ten szczególny kłopot ... jeśli chcesz pominąć elementy, po prostu użyj continue w ciele pętli.

I tak dla kompletności, w zależności od tego, co robiłeś ze swoim indeksem( powyższe konstrukcje oferują dużą elastyczność), możesz użyć Parallel LINQ:

// First, filter 'e' based on 'i',
// then apply an action to remaining 'e'
collection
    .AsParallel()
    .Where((e,i) => /* filter with e,i */)
    .ForAll(e => { /* use e, but don't modify it */ });

// Using 'e' and 'i', produce a new collection,
// where each element incorporates 'i'
collection
    .AsParallel()
    .Select((e, i) => new MyWrapper(e, i));

We użyj AsParallel() powyżej, ponieważ jest już rok 2014 i chcemy dobrze wykorzystać te wiele rdzeni, aby przyspieszyć działanie. Ponadto, dla' sekwencyjnego ' LINQ, otrzymujesz tylko ForEach() metodę rozszerzenia na List<T> i Array ... i nie jest jasne, że używanie go jest lepsze niż robienie prostego foreach, ponieważ nadal używasz jednowątkowego dla brzydszej składni.

 15
Author: David Bullock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:27

Używając LINQ, C # 7 i pakietu System.ValueTuple NuGet, możesz to zrobić:

foreach (var (value, index) in collection.Select((v, i)=>(v, i))) {
    Console.WriteLine(value + " is at index " + index);
}

Możesz użyć zwykłej konstrukcji foreach i mieć bezpośredni dostęp do wartości i indeksu, a nie jako członek obiektu, i przechowywać oba pola tylko w zakresie pętli. Z tych powodów uważam, że jest to najlepsze rozwiązanie, jeśli jesteś w stanie używać C # 7 i System.ValueTuple.

 14
Author: Pavel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-18 15:57:38
int index;
foreach (Object o in collection)
{
    index = collection.indexOf(o);
}

Będzie to działać dla zbiorów wspierających IList.

 12
Author: Sachin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-02 03:50:06

Będzie działać tylko dla listy, a nie dla jakiejś liczby, ale w LINQ jest to:

IList<Object> collection = new List<Object> { 
    new Object(), 
    new Object(), 
    new Object(), 
    };

foreach (Object o in collection)
{
    Console.WriteLine(collection.IndexOf(o));
}

Console.ReadLine();

@Jonathan nie powiedziałem, że to świetna odpowiedź, tylko powiedziałem, że to tylko pokazanie, że można zrobić to, o co prosił:)

@Graphain nie spodziewałbym się, że będzie szybko - nie jestem do końca pewien, jak to działa, za każdym razem można by powtórzyć całą listę, aby znaleźć pasujący obiekt, który byłby helluvalot porównań.

To powiedziawszy, lista może przechowywać indeks każdego / align = "left" /

Jonathan wydaje się mieć lepszy pomysł, jeśli mógłby to rozwinąć?

Byłoby lepiej po prostu liczyć, gdzie jesteś w foreach choć, prostsze, i bardziej elastyczne.

 9
Author: crucible,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 02:51:31

Tak to robię, co jest miłe ze względu na swoją prostotę/zwięzłość, ale jeśli robisz dużo w ciele pętli obj.Value, to szybko się zestarzeje.

foreach(var obj in collection.Select((item, index) => new { Index = index, Value = item }) {
    string foo = string.Format("Something[{0}] = {1}", obj.Index, obj.Value);
    ...
}
 8
Author: Ian Henry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-28 11:52:49

C # 7 wreszcie daje nam elegancki sposób na to:

static class Extensions
{
    public static IEnumerable<(int, T)> Enumerate<T>(
        this IEnumerable<T> input,
        int start = 0
    )
    {
        int i = start;
        foreach (var t in input)
        {
            yield return (i++, t);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var s = new string[]
        {
            "Alpha",
            "Bravo",
            "Charlie",
            "Delta"
        };

        foreach (var (i, t) in s.Enumerate())
        {
            Console.WriteLine($"{i}: {t}");
        }
    }
}
 8
Author: Paul Mitchell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-21 13:52:17

Dlaczego foreach ?!

Najprostszym sposobem jest użycie dla zamiast foreach , Jeśli używasz List .

for(int i = 0 ; i < myList.Count ; i++)
{
    // Do Something...
}

Lub jeśli chcesz użyć foreach:

foreach (string m in myList)
{
     // Do something...       
}

Możesz użyć tego do indeksu khow każdej pętli:

myList.indexOf(m)
 7
Author: Parsa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-26 21:41:22

Lepiej użyć słowa kluczowego continue bezpieczna konstrukcja jak Ta

int i=-1;
foreach (Object o in collection)
{
    ++i;
    //...
    continue; //<--- safe to call, index will be increased
    //...
}
 6
Author: user426810,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-26 14:49:57

Myślę, że to nie powinno być dość wydajne, ale działa:

@foreach (var banner in Model.MainBanners) {
    @Model.MainBanners.IndexOf(banner)
}
 4
Author: Bart Calixto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-28 11:54:51

Zbudowałem to w LINQPad :

var listOfNames = new List<string>(){"John","Steve","Anna","Chris"};

var listCount = listOfNames.Count;

var NamesWithCommas = string.Empty;

foreach (var element in listOfNames)
{
    NamesWithCommas += element;
    if(listOfNames.IndexOf(element) != listCount -1)
    {
        NamesWithCommas += ", ";
    }
}

NamesWithCommas.Dump();  //LINQPad method to write to console.

Możesz też użyć string.join:

var joinResult = string.Join(",", listOfNames);
 4
Author: Warren LaFrance,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-28 11:58:54

Jeśli kolekcja jest listą, możesz użyć List.IndexOf, jak w:

foreach (Object o in collection)
{
    // ...
    @collection.IndexOf(o)
}
 4
Author: ssaeed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-04 03:06:12

Nie wierzę, że istnieje sposób na uzyskanie wartości bieżącej iteracji pętli foreach. Liczenie siebie wydaje się być najlepszym sposobem.

Mogę zapytać, dlaczego chcesz wiedzieć?

Wygląda na to, że najchętniej zrobiłbyś jedną z trzech rzeczy:

1) uzyskanie obiektu z kolekcji, ale w tym przypadku już go masz.

2) liczenie obiektów do późniejszego przetwarzania końcowego...zbiory mają własność Count, którą można wykorzystać z.

3) ustawienie właściwości obiektu na podstawie jego kolejności w pętli...chociaż można łatwo ustawić, że po dodaniu obiektu do kolekcji.

 3
Author: bryansh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 01:53:50

Moim rozwiązaniem tego problemu jest metoda rozszerzenia WithIndex(),

Http://code.google.com/p/ub-dotnet-utilities/source/browse/trunk/Src/Utilities/Extensions/EnumerableExtensions.cs

Użyj go jak

var list = new List<int> { 1, 2, 3, 4, 5, 6 };    

var odd = list.WithIndex().Where(i => (i.Item & 1) == 1);
CollectionAssert.AreEqual(new[] { 0, 2, 4 }, odd.Select(i => i.Index));
CollectionAssert.AreEqual(new[] { 1, 3, 5 }, odd.Select(i => i.Item));
 3
Author: ulrichb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-14 21:10:53

Może coś takiego? Zauważ, że myDelimitedString może być null, jeśli myenumerable jest puste.

IEnumerator enumerator = myEnumerable.GetEnumerator();
string myDelimitedString;
string current = null;

if( enumerator.MoveNext() )
    current = (string)enumerator.Current;

while( null != current)
{
    current = (string)enumerator.Current; }

    myDelimitedString += current;

    if( enumerator.MoveNext() )
        myDelimitedString += DELIMITER;
    else
        break;
}
 3
Author: Matt Towers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-29 19:27:25

Dla zainteresowania, Phil Haack właśnie napisał przykład tego w kontekście delegata szablonowego Razora (http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx )

Efektywnie pisze metodę rozszerzenia, która owija iterację w klasę "IteratedItem" (patrz niżej) pozwalającą na dostęp do indeksu, jak również elementu podczas iteracji.

public class IndexedItem<TModel> {
  public IndexedItem(int index, TModel item) {
    Index = index;
    Item = item;
  }

  public int Index { get; private set; }
  public TModel Item { get; private set; }
}

Jednak, podczas gdy byłoby to w porządku w środowisku nie-Razor, jeśli wykonujesz pojedynczą operację (tj. taki, który może być dostarczony jako lambda) nie będzie to solidne zastąpienie składni for / foreach w kontekstach innych niż brzytwa.

 3
Author: Matt Mitchell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 23:25:15

Nie byłem pewien, co próbujesz zrobić z informacjami o indeksie na podstawie pytania. Jednak w C# zazwyczaj można dostosować liczbę.Wybierz metodę, aby uzyskać Indeks z dowolnego, co chcesz. Na przykład, mogę użyć czegoś takiego, czy wartość jest nieparzysta, czy parzysta.

string[] names = { "one", "two", "three" };
var oddOrEvenByName = names
    .Select((name, index) => new KeyValuePair<string, int>(name, index % 2))
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

To da ci słownik z nazwą tego, czy element był nieparzysty (1) Czy parzysty (0) na liście.

 3
Author: Kasey Speakman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-14 19:03:54

Możesz napisać pętlę tak:

var s = "ABCDEFG";
foreach (var item in s.GetEnumeratorWithIndex())
{
    System.Console.WriteLine("Character: {0}, Position: {1}", item.Value, item.Index);
}

Po dodaniu następującej metody struct i extension.

Metoda struct i extension zawiera Enumerable.Wybierz opcję funkcjonalność.

public struct ValueWithIndex<T>
{
    public readonly T Value;
    public readonly int Index;

    public ValueWithIndex(T value, int index)
    {
        this.Value = value;
        this.Index = index;
    }

    public static ValueWithIndex<T> Create(T value, int index)
    {
        return new ValueWithIndex<T>(value, index);
    }
}

public static class ExtensionMethods
{
    public static IEnumerable<ValueWithIndex<T>> GetEnumeratorWithIndex<T>(this IEnumerable<T> enumerable)
    {
        return enumerable.Select(ValueWithIndex<T>.Create);
    }
}
 3
Author: Satisfied,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-23 15:48:03

Odpowiedź wiodąca brzmi:

"Oczywiście, pojęcie indeksu jest obce pojęciu wyliczenia i nie można tego zrobić."

Chociaż dotyczy to obecnej wersji C#, nie jest to limit pojęciowy.

W przeciwieństwie do innych języków C#, C # nie jest w pełni kompatybilny z C#, ale z C # # # # # # # # # # # ]}
foreach (var item in collection with var index)
{
    Console.WriteLine("Iteration {0} has value {1}", index, item);
}

//or, building on @user1414213562's answer
foreach (var (item, index) in collection)
{
    Console.WriteLine("Iteration {0} has value {1}", index, item);
}

Jeśli foreach jest przekazywany jako IEnumerable i nie można go rozwiązać, ale jest pytany z indeksem var, następnie kompilator C# może zawinąć Źródło za pomocą obiektu IndexedEnumerable, który dodaje kod do śledzenia indeksu.

interface IIndexedEnumerable<T> : IEnumerable<T>
{
    //Not index, because sometimes source IEnumerables are transient
    public long IterationNumber { get; }
}

Dlaczego:

    Foreach wygląda ładniej, a w aplikacjach biznesowych rzadko jest wąskim gardłem wydajności.]}
  • Foreach może być bardziej wydajny w pamięci. Posiadanie potoku funkcji zamiast konwersji do nowych kolekcji na każdym kroku. Kogo obchodzi, czy wykorzystuje kilka cykli procesora więcej, jeśli jest mniej błędów pamięci podręcznej procesora i mniej GC.Zbiera
  • wymaganie od kodera dodania kodu śledzącego indeks, psuje piękno
  • Jest dość łatwy w implementacji (dzięki MS) i jest kompatybilny wstecz [16]}

Podczas gdy większość ludzi tutaj nie jest MS, jest to poprawna odpowiedź i możesz lobbować MS, aby dodać taką funkcję. Można już zbudować własny iterator z funkcją rozszerzenia i używać krotek, ale MS może posypać cukrem składniowym, aby uniknąć funkcji rozszerzenia

 3
Author: Todd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-20 01:16:45

Jeśli Twoja kolekcja nie może zwrócić indeksu obiektu za pomocą jakiejś metody, jedynym sposobem jest użycie licznika, jak w twoim przykładzie.

Jednak, podczas pracy z indeksami, jedyną rozsądną odpowiedzią na problem jest użycie pętli for. Wszystko inne wprowadza złożoność kodu, nie wspominając o złożoności czasu i przestrzeni.

 2
Author: Joseph Daigle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 02:50:16

Właśnie miałem ten problem, ale przemyślenie problemu w moim przypadku dało najlepsze rozwiązanie, niezwiązane z oczekiwanym rozwiązaniem.

Może to być dość powszechny przypadek, w zasadzie czytam z jednej listy źródłowej i tworzę obiekty na ich podstawie na liście docelowej, jednak muszę najpierw sprawdzić, czy pozycje źródłowe są poprawne i chcę zwrócić wiersz błędu. Na pierwszy rzut oka chcę wprowadzić indeks do wyliczenia obiektu w bieżącej właściwości, jednak, ponieważ kopiuję te elementy, domyślnie i tak znam bieżący indeks z bieżącego miejsca docelowego. Oczywiście zależy to od obiektu docelowego, ale dla mnie była to lista i najprawdopodobniej zaimplementuje kolekcję.

Tzn.

var destinationList = new List<someObject>();
foreach (var item in itemList)
{
  var stringArray = item.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);

  if (stringArray.Length != 2)
  {
    //use the destinationList Count property to give us the index into the stringArray list
    throw new Exception("Item at row " + (destinationList.Count + 1) + " has a problem.");
  }
  else
  {
    destinationList.Add(new someObject() { Prop1 = stringArray[0], Prop2 = stringArray[1]});
  }
}

Nie zawsze dotyczy, ale na tyle często, że warto o tym wspomnieć, myślę.

W każdym razie, chodzi o to, że czasami istnieje nieoczywiste rozwiązanie już w logice, którą masz...

 2
Author: nicodemus13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 12:34:52

To nie odpowiada na konkretne pytanie, ale daje rozwiązanie problemu: użyj pętli for, aby uruchomić kolekcję obiektów. następnie będziesz mieć bieżący indeks, nad którym pracujesz.

// Untested
for (int i = 0; i < collection.Count; i++)
{
    Console.WriteLine("My index is " + i);
}
 1
Author: BKSpurgeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-02 02:11:08