foreach loops ทำงานอย่างไรใน C #? [ปิด]


86

ประเภทของคลาสforeachใดบ้างที่สามารถใช้ลูปได้?


5
คุณอาจต้องการเลือกคำตอบอื่นที่ยอมรับได้เนื่องจากคำตอบที่คุณเลือกไม่ได้เป็นตัวแทนของคำตอบที่ถูกต้อง
George Stocker

คำตอบ:


162

จริงๆแล้วพูดอย่างเคร่งครัดสิ่งที่คุณต้องใช้foreachคือGetEnumerator()วิธีสาธารณะที่ส่งคืนบางสิ่งด้วยbool MoveNext()วิธีการและ? Current {get;}คุณสมบัติ แต่ส่วนใหญ่ที่พบความหมายของนี้คือ "สิ่งที่ดำเนินการIEnumerable/ IEnumerable<T>กลับ/IEnumeratorIEnumerator<T>

โดยปริยายนี้รวมถึงสิ่งที่ดำเนินการICollection/ ICollection<T>เช่นอะไรเช่นCollection<T>, List<T>อาร์เรย์ ( T[]) ฯลฯ ดังนั้น "การเก็บรวบรวมข้อมูล" มาตรฐานใด ๆ foreachโดยทั่วไปจะสนับสนุน

สำหรับการพิสูจน์จุดแรกสิ่งต่อไปนี้ใช้ได้ดี:

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

มันทำงานอย่างไร?

foreach loop เช่นforeach(int i in obj) {...}kinda เท่ากับ:

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

อย่างไรก็ตามมีรูปแบบต่างๆ ตัวอย่างเช่นหาก enumerator (tmp) รองรับIDisposableก็จะใช้ด้วย (คล้ายกับusing)

สังเกตความแตกต่างของตำแหน่งของการประกาศ " int i" ภายใน (C # 5.0) กับภายนอก (ขึ้น C # 4.0) ของลูป เป็นสิ่งสำคัญหากคุณใช้iในวิธีการแบบไม่ระบุตัวตน / แลมบ์ดาภายในโค้ดบล็อกของคุณ แต่นั่นก็เป็นอีกเรื่องหนึ่ง ;-p


3
+1 สำหรับการเจาะลึก โดยปกติฉันจะไม่เจาะลึกขนาดนั้นสำหรับคำถามที่อาจเป็นคำถาม 'สำหรับผู้เริ่มต้น' เพราะโปรแกรมเมอร์หน้าใหม่ดูเหมือนจะหนักใจ
George Stocker

จริง Gortok - ดังนั้นฉันจึงติดตามข้อมูลเกี่ยวกับรายการ / อาร์เรย์ / ฯลฯ
Marc Gravell

จะเป็นการดีที่จะกล่าวถึงการแคสต์รันไทม์โดยนัยไปยังตัวแปรลูป - สามารถสร้างข้อยกเว้นประเภทที่เข้ากันไม่ได้
Daniel Earwicker

3
อย่าลืม: เมื่อใช้อาร์เรย์กับ foreach คอมไพเลอร์จะสร้างแบบง่ายfor-loop(คุณจะเห็นสิ่งนี้เมื่อทำงานกับ IL)
Felix K.

1
@Marc Gravell: โอเคเจ๋ง! ฉันแก้ไขโพสต์เพื่อให้ชัดเจนยิ่งขึ้น - อย่างน้อยก็สำหรับฉัน หลังจากที่ทุกตำแหน่งไม่ได้มีความสำคัญเพียงอย่างเดียวใน C # 5.0 แต่ก็สำคัญเสมอเพียงแต่ว่าตำแหน่งนั้นเปลี่ยนไป หวังว่าคงไม่เป็นไร
Paul Groke

7

จากMSDN :

foreachคำสั่งซ้ำกลุ่มของงบที่ฝังตัวสำหรับแต่ละองค์ประกอบในอาร์เรย์หรือการเก็บรวบรวมวัตถุ foreachคำสั่งที่ใช้ในการย้ำผ่านคอลเลกชันที่จะได้รับข้อมูลที่ต้องการ แต่ไม่ควรนำมาใช้เพื่อเปลี่ยนเนื้อหาของคอลเลกชันที่จะหลีกเลี่ยงผลข้างเคียงที่คาดเดาไม่ได้ (เน้นของฉัน)

ดังนั้นหากคุณมีอาร์เรย์คุณสามารถใช้คำสั่ง foreach เพื่อวนซ้ำผ่านอาร์เรย์ได้ดังนี้:

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

คุณยังสามารถใช้เพื่อวนซ้ำผ่านList<T>คอลเลคชันได้เช่น:

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

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

4
ผิดปกติพอตาม MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ) ประเภทวัตถุไม่จำเป็นต้องใช้ IEnumerable ทุกประเภทที่กำหนด GetEnumerator, MoveNext, Reset และ Current วิธีที่ถูกต้องจะใช้ได้ผล แปลกใช่มั้ย?
Sean Reilly

เรียบร้อย. ฉันไม่รู้เรื่องนั้น :-)
George Stocker


2

นี่คือเอกสาร: บทความหลักเกี่ยว กับ Arrays With Collection Objects

โปรดทราบว่า "ประเภทขององค์ประกอบคอลเลกชันต้องสามารถแปลงเป็นประเภทตัวระบุได้" บางครั้งไม่สามารถตรวจสอบได้ในเวลาคอมไพล์และสามารถสร้างข้อยกเว้นรันไทม์ได้หากไม่สามารถกำหนดประเภทอินสแตนซ์ให้กับประเภทการอ้างอิง

สิ่งนี้จะสร้างข้อยกเว้นรันไทม์หากไม่มี Apple อยู่ในตะกร้าผลไม้เช่นส้ม

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

สิ่งนี้กรองรายการได้อย่างปลอดภัยเฉพาะแอปเปิ้ลโดยใช้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

ข้อมูลที่เป็นประโยชน์เกี่ยวกับเรื่องนี้สามารถพบได้ในMSDNด้วย นำสาระสำคัญจากบทความนั้น:

คีย์เวิร์ด foreach จะระบุคอลเล็กชันโดยเรียกใช้คำสั่งฝังตัวหนึ่งครั้งสำหรับแต่ละองค์ประกอบในคอลเลกชัน:

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

คอมไพเลอร์แปล foreach loop ที่แสดงในตัวอย่างด้านบนเป็นสิ่งที่คล้ายกับโครงสร้างนี้:

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

-2

คุณสามารถลองสิ่งนี้ ...

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);
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.