Các vòng lặp foreach hoạt động như thế nào trong C #? [đóng cửa]


86

Những loại lớp nào có thể sử dụng foreachvòng lặp?


5
Bạn có thể muốn chọn một câu trả lời được chấp nhận khác, vì câu bạn đã chọn không thực sự đại diện cho câu trả lời đúng.
George Stocker

Câu trả lời:


162

Trên thực tế, Nghiêm nói, tất cả các bạn cần phải sử dụng foreachlà một công GetEnumerator()phương pháp mà lợi nhuận gì đó với một bool MoveNext()phương pháp và một ? Current {get;}tài sản. Tuy nhiên, ý nghĩa phổ biến nhất của điều này là "cái gì đó thực hiện IEnumerable/ IEnumerable<T>, trả về một IEnumerator/ IEnumerator<T>.

Ngụ ý, điều này bao gồm bất cứ điều gì cụ ICollection/ ICollection<T>, như bất cứ điều gì giống như Collection<T>, List<T>, mảng ( T[]), vv Vì vậy, bất kỳ "thu thập dữ liệu" tiêu chuẩn sẽ thường hỗ trợ foreach.

Để chứng minh cho điểm đầu tiên, những điều sau đây hoạt động tốt:

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);
        }
    }
}

Làm thế nào nó hoạt động?

Một vòng lặp foreach như foreach(int i in obj) {...}kinda tương đương với:

var tmp = obj.GetEnumerator();
int i; // up to C# 4.0
while(tmp.MoveNext()) {
    int i; // C# 5.0
    i = tmp.Current;
    {...} // your code
}

Tuy nhiên, có những biến thể. Ví dụ, nếu điều tra viên (tmp) hỗ trợ IDisposable, nó cũng được sử dụng (tương tự như using).

Lưu ý sự khác biệt về vị trí của khai báo " int i" bên trong (C # 5.0) so với bên ngoài (lên C # 4.0) vòng lặp. Điều quan trọng nếu bạn sử dụng itrong một phương thức ẩn danh / lambda bên trong khối mã của bạn. Nhưng đó là một câu chuyện khác ;-p


3
+1 để đi sâu. Tôi thường không đi sâu về vấn đề đó cho một câu hỏi có thể là câu hỏi dành cho người mới bắt đầu vì nó có vẻ quá sức đối với lập trình viên mới.
George Stocker

Đúng, Gortok - vì vậy tôi đã theo dõi nội dung về danh sách / mảng / vv.
Marc Gravell

Sẽ rất tốt nếu đề cập đến việc truyền thời gian chạy ngầm định đến biến vòng lặp - có thể tạo ra các ngoại lệ không tương thích kiểu.
Daniel Earwicker

3
Đừng quên: Khi sử dụng một mảng với foreach, trình biên dịch sẽ tạo ra một sự đơn giản for-loop(Bạn có thể thấy điều này khi làm việc với IL).
Felix K.

1
@Marc Gravell: OK, tuyệt! Tôi đã chỉnh sửa bài đăng để làm cho nó rõ ràng hơn - ít nhất là đối với tôi. Sau tất cả, vị trí không chỉ quan trọng trong C # 5.0, nó luôn quan trọng, chỉ là nó đã thay đổi. Tôi hy vọng bạn không phiền.
Paul Groke

7

Từ MSDN :

Câu foreachlệnh lặp lại một nhóm câu lệnh nhúng cho mỗi phần tử trong một mảng hoặc một tập hợp đối tượng . Câu foreachlệnh được sử dụng để lặp qua bộ sưu tập để có được thông tin mong muốn, nhưng không nên dùng để thay đổi nội dung của bộ sưu tập để tránh các tác dụng phụ không thể đoán trước. (nhấn mạnh của tôi)

Vì vậy, nếu bạn có một mảng, bạn có thể sử dụng câu lệnh foreach để lặp qua mảng, như sau:

 int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
    foreach (int i in fibarray)
    {
        System.Console.WriteLine(i);
    }

Bạn cũng có thể sử dụng nó để lặp lại qua một List<T>bộ sưu tập, như sau:

List<string> list = new List<string>();

foreach (string item in list)
{
    Console.WriteLine(item);
}

4
kỳ lạ thay, theo MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ), các loại đối tượng không cần triển khai IEnumerable. Bất kỳ loại nào xác định GetEnumerator, MoveNext, Reset và Current theo cách chính xác sẽ hoạt động. Kỳ lạ, phải không?
Sean Reilly

Khéo léo. Tôi không biết điều đó. :-)
George Stocker 29/12/08


2

Đây là tài liệu: Bài viết chính Với Mảng Với Đối tượng Bộ sưu tập

Điều quan trọng cần lưu ý là "Loại phần tử tập hợp phải có thể chuyển đổi thành loại định danh". Điều này đôi khi không thể được kiểm tra tại thời điểm biên dịch và có thể tạo ra một ngoại lệ thời gian chạy nếu kiểu thể hiện không thể gán cho kiểu tham chiếu.

Điều này sẽ tạo ra một ngoại lệ thời gian chạy nếu có một quả không phải là Apple trong giỏ trái cây, chẳng hạn như một quả cam.

List<Fruit> fruitBasket = new List<Fruit>() { new Apple(), new Orange() };
foreach(Apple a in fruitBasket)

Điều này sẽ lọc danh sách một cách an toàn chỉ những Táo bằng Enumerable.OfType

foreach(Apple a in fruitBasket.OfType<Apple>() )

-1
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);
    }
}

-1

Thông tin hữu ích về chủ đề này cũng có thể được tìm thấy trên MSDN . Lấy cốt lõi từ bài báo đó:

Từ khóa foreach liệt kê một tập hợp, thực hiện câu lệnh nhúng một lần cho mỗi phần tử trong tập hợp:

foreach (var item in collection)
{
    Console.WriteLine(item.ToString());
}

Trình biên dịch dịch vòng lặp foreach được hiển thị trong ví dụ trên thành một thứ tương tự như cấu trúc này:

IEnumerator<int> enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
    var item = enumerator.Current;
    Console.WriteLine(item.ToString());
}

-2

bạn có thể thử cái này ...

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);
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.