Możesz wybrać inną zaakceptowaną odpowiedź, ponieważ ta, którą wybrałeś, nie jest reprezentatywna dla poprawnej odpowiedzi.
George Stocker
Odpowiedzi:
162
Właściwie, ściśle rzecz biorąc, wszystko, czego potrzebujesz, foreachto GetEnumerator()metoda publiczna , która zwraca coś z bool MoveNext()metodą i ? Current {get;}właściwością. Jednak najczęstszym znaczeniem tego jest „coś, co implementuje IEnumerable/ IEnumerable<T>, zwracając IEnumerator/ IEnumerator<T>.
W sposób dorozumiany, obejmuje to wszystko, narzędzia ICollection/ ICollection<T>, jak coś podobnego Collection<T>, List<T>tablice ( T[]), itd. Tak więc każdego standardowego „zbiór danych” będzie generalnie wspierać foreach.
W celu potwierdzenia pierwszego punktu, poniższe działa dobrze:
using System;
classFoo {
publicint Current { get; privateset; }
privateint step;
publicboolMoveNext() {
if (step >= 5) returnfalse;
Current = step++;
returntrue;
}
}
classBar {
public Foo GetEnumerator() { returnnew Foo(); }
}
staticclassProgram {
staticvoidMain() {
Bar bar = new Bar();
foreach (int item in bar) {
Console.WriteLine(item);
}
}
}
Jak to działa?
Każda pętla, taka jak foreach(int i in obj) {...}rodzaj, równa się:
var tmp = obj.GetEnumerator();
int i; // up to C# 4.0while(tmp.MoveNext()) {
int i; // C# 5.0
i = tmp.Current;
{...} // your code
}
Istnieją jednak różnice. Na przykład, jeśli moduł wyliczający (tmp) obsługuje IDisposable, jest również używany (podobnie jak using).
Zwróć uwagę na różnicę w umieszczaniu deklaracji „ int i” wewnątrz (C # 5,0) w porównaniu z zewnętrzną (w C # 4,0) pętli. Jest to ważne, jeśli używasz ianonimowej metody / lambdy wewnątrz bloku kodu. Ale to już inna historia ;-p
+1 za pogłębienie. Zwykle nie zagłębiam się w pytanie, które może być pytaniem dla początkujących, ponieważ dla nowego programisty wydawałoby się to przytłaczające.
George Stocker
To prawda, Gortok - więc poszedłem do rzeczy o listach / tablicach / itd.
Marc Gravell
Dobrze byłoby wspomnieć o niejawnym rzutowaniu środowiska uruchomieniowego na zmienną pętli - może generować wyjątki niezgodności typów.
Daniel Earwicker,
3
Nie zapomnij: Używając tablicy z foreach, kompilator tworzy prosty for-loop(widać to podczas pracy z IL).
Felix K.
1
@Marc Gravell: OK, super! Zredagowałem post, aby był bardziej zrozumiały - przynajmniej dla mnie. W końcu umiejscowienie jest nie tylko ważne w C # 5.0, ale jest zawsze ważne, tylko że się zmieniło. Mam nadzieję, że nie masz nic przeciwko.
foreachStwierdzenie powtarza grupę wbudowane instrukcje dla każdego elementu macierzy lub zbiór obiektów . foreachOświadczenie jest używany do iteracji kolekcji, aby uzyskać żądaną informację, ale nie powinny być wykorzystywane do zmiany zawartości kolekcji uniknąć nieprzewidywalnych skutków ubocznych. (podkreślenie moje)
Więc jeśli masz tablicę, możesz użyć instrukcji foreach do iteracji po tablicy, na przykład:
co dziwne, zgodnie z MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ) typy obiektów nie muszą implementować IEnumerable. Każdy typ, który poprawnie definiuje GetEnumerator, MoveNext, Reset i Current będzie działał. Dziwne, co?
Sean Reilly
Schludny. Nie wiedziałem tego. :-)
George Stocker
4
Zgodnie z wpisem na blogu Duck Notation , używane jest pisanie kaczka.
Należy zauważyć, że „Typ elementu kolekcji musi być możliwy do przekonwertowania na typ identyfikatora”. Czasami nie można tego sprawdzić w czasie kompilacji i może wygenerować wyjątek czasu wykonywania, jeśli typu wystąpienia nie można przypisać do typu referencyjnego.
Spowoduje to wygenerowanie wyjątku czasu wykonywania, jeśli w koszyku z owocami znajduje się produkt inny niż Apple, na przykład pomarańcza.
List<Fruit> fruitBasket = new List<Fruit>() { new Apple(), new Orange() };
foreach(Apple a in fruitBasket)
To bezpiecznie filtruje listę tylko do jabłek przy użyciu Enumerable.OfType
List<int> numbers = new List<int>();
numbers.Add(5);
numbers.Add(15);
numbers.Add(25);
numbers.Add(35);
Console.WriteLine("You are added total number: {0}",numbers.Count);
foreach (int number in numbers)
{
Console.WriteLine("Your adding Number are: {0}", number);
}
Odpowiedzi:
Właściwie, ściśle rzecz biorąc, wszystko, czego potrzebujesz,
foreach
toGetEnumerator()
metoda publiczna , która zwraca coś zbool MoveNext()
metodą i? Current {get;}
właściwością. Jednak najczęstszym znaczeniem tego jest „coś, co implementujeIEnumerable
/IEnumerable<T>
, zwracającIEnumerator
/IEnumerator<T>
.W sposób dorozumiany, obejmuje to wszystko, narzędzia
ICollection
/ICollection<T>
, jak coś podobnegoCollection<T>
,List<T>
tablice (T[]
), itd. Tak więc każdego standardowego „zbiór danych” będzie generalnie wspieraćforeach
.W celu potwierdzenia pierwszego punktu, poniższe działa dobrze:
using System; class Foo { public int Current { get; private set; } private int step; public bool MoveNext() { if (step >= 5) return false; Current = step++; return true; } } class Bar { public Foo GetEnumerator() { return new Foo(); } } static class Program { static void Main() { Bar bar = new Bar(); foreach (int item in bar) { Console.WriteLine(item); } } }
Jak to działa?
Każda pętla, taka jak
foreach(int i in obj) {...}
rodzaj, równa się:var tmp = obj.GetEnumerator(); int i; // up to C# 4.0 while(tmp.MoveNext()) { int i; // C# 5.0 i = tmp.Current; {...} // your code }
Istnieją jednak różnice. Na przykład, jeśli moduł wyliczający (tmp) obsługuje
IDisposable
, jest również używany (podobnie jakusing
).Zwróć uwagę na różnicę w umieszczaniu deklaracji „
int i
” wewnątrz (C # 5,0) w porównaniu z zewnętrzną (w C # 4,0) pętli. Jest to ważne, jeśli używaszi
anonimowej metody / lambdy wewnątrz bloku kodu. Ale to już inna historia ;-pźródło
for-loop
(widać to podczas pracy z IL).Z MSDN :
Więc jeśli masz tablicę, możesz użyć instrukcji foreach do iteracji po tablicy, na przykład:
int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 }; foreach (int i in fibarray) { System.Console.WriteLine(i); }
Możesz go również użyć do iteracji w
List<T>
kolekcji, na przykład:List<string> list = new List<string>(); foreach (string item in list) { Console.WriteLine(item); }
źródło
Zgodnie z wpisem na blogu Duck Notation , używane jest pisanie kaczka.
źródło
Oto dokumentacja: Główny artykuł z tablicami z obiektami kolekcji
Należy zauważyć, że „Typ elementu kolekcji musi być możliwy do przekonwertowania na typ identyfikatora”. Czasami nie można tego sprawdzić w czasie kompilacji i może wygenerować wyjątek czasu wykonywania, jeśli typu wystąpienia nie można przypisać do typu referencyjnego.
Spowoduje to wygenerowanie wyjątku czasu wykonywania, jeśli w koszyku z owocami znajduje się produkt inny niż Apple, na przykład pomarańcza.
List<Fruit> fruitBasket = new List<Fruit>() { new Apple(), new Orange() }; foreach(Apple a in fruitBasket)
To bezpiecznie filtruje listę tylko do jabłek przy użyciu Enumerable.OfType
foreach(Apple a in fruitBasket.OfType<Apple>() )
źródło
IList<ListItem> illi = new List<ListItem>(); ListItem li = null; foreach (HroCategory value in listddlsubcategory) { listddlsubcategoryext = server.getObjectListByColumn(typeof(HroCategory), "Parentid", value.Id); li = new ListItem(); li.Text = value.Description; li.Value = value.Id.ToString(); illi.Add(li); IList<ListItem> newilli = new List<ListItem>(); newilli = SubCatagoryFunction(listddlsubcategoryext, "-->"); foreach (ListItem c in newilli) { illi.Add(c); } }
źródło
Przydatne informacje na ten temat można również znaleźć w witrynie MSDN . Biorąc esencję z tego artykułu:
Słowo kluczowe foreach wylicza kolekcję, wykonując instrukcję embedded raz dla każdego elementu w kolekcji:
foreach (var item in collection) { Console.WriteLine(item.ToString()); }
Kompilator tłumaczy pętlę foreach pokazaną w powyższym przykładzie na coś podobnego do tej konstrukcji:
IEnumerator<int> enumerator = collection.GetEnumerator(); while (enumerator.MoveNext()) { var item = enumerator.Current; Console.WriteLine(item.ToString()); }
źródło
możesz spróbować tego ...
List<int> numbers = new List<int>(); numbers.Add(5); numbers.Add(15); numbers.Add(25); numbers.Add(35); Console.WriteLine("You are added total number: {0}",numbers.Count); foreach (int number in numbers) { Console.WriteLine("Your adding Number are: {0}", number); }
źródło