C#.NET Yield Return

สวัสดีครับ

ขอเขียนบล็อคแบบสั้นๆอธิบายเรื่อง yield return ซึ่งเป็นฟีเจอร์หนึ่ง ในภาษา C#

บ่อยครั้ง เราต้องทำงานกับ collection โดยการ loop เข้าไปใน collection หนึ่ง ตัวอย่าง collection ที่เป็นผลจาก function นี้


public static List GenOdd(int max)
{
     var results = new List();
     foreach (var n in Enumerable.Range(1, max))
    {
        if(n % 3 == 0) results.Add(n);
    }
    return results;
}

ตัวอย่าง ตอนใช้งาน ผมต้องการหยุด หรือ เมื่อเงื่อนไขสำเร็จ ตัวอย่างนี้ผมให้หยุด loop ที่ item == 11


static void Main(string[] args)
{

    foreach (var item in FindOddYield(1000000))
    {
        if (item == 11) break;
    }
}

ซึ่ง code อาจจะไม่เห็นว่า ผม loop[ ไปเท่าไร ผมก็เลยลองเพิ่มตัวแปร Spy เพื่อนับครั้งใน function FindOdd เพื่อจะได้รู้ว่ามัน loop ไปกี่ครั้ง code จะเปลี่ยนไปเล็กน้อย แบบนี้


int SpyCallCount = 0;
public List GenOdd(int max)
{
    var results = new List();
    foreach (var n in Enumerable.Range(1, max))
    {
        ++SpyCallCount;
        if(n % 3 == 0) results.Add(n);
    }
    return results;
}

ทีนี้ลอง ใช้งานดูครับ แต่ให้แสดง SpyCallCount ออกมาด้วย

static void Main(string[] args)
{
    foreach (var item in FindOddYield(1000000))
    {
        if (item == 11) break;

        Console.WriteLine(SpyCallCount); // print 1000000
    }
}

จะเห็นว่า SpyCallCount เท่ากับ 100000 ซึ่งเราต้องการหยุดที่ item เท่ากับ 11 เท่านั้น แต่ function ของเราไม่หยุดทำงาน

เรามาทำให้ function แบบนี้ดีขึ้นดีกว่า โดยการใช้ฟีเจอร์ yield return กลับไป แก้ไข function GenOdd แบบนี้

int SpyCallCount = 0;
public IEnumerable GenOdd(int max)
{
    foreach (var n in Enumerable.Range(1, max))
    {
        ++SpyCallCount;
        if(n % 3 == 0) yield return n;
    }
}

ทีนี้กลับไปลองใช้ใหม่ คุณจะเห็นผลลัพธ์ SpyCallCount เท่ากับ 11 แสดงให้เห็นว่า loop ลดลงเยอะเลยใช่มั้ยครับ นั่นคือลดการใช้ CPU time ลงไปตามงานที่เราต้องการ ไม่วนเล่นสูญเปล่าไปเฉยๆ

ก็ขอแชร์ไว้แค่นี้ ไปลองประยุกต์ใช้ yield return กันดู แนะนำมีประโยชน์ครับ

ขอบคุณครับ

#:P

#iterator-patterns, #yield-return

Advertisements