Eric Lippert ได้เขียนบทความที่ยอดเยี่ยมเกี่ยวกับข้อ จำกัด (และการตัดสินใจออกแบบที่มีอิทธิพลต่อตัวเลือกเหล่านั้น) ในบล็อกตัวทำซ้ำ
โดยเฉพาะบล็อกตัววนซ้ำจะถูกนำไปใช้โดยการแปลงโค้ดคอมไพลเลอร์ที่ซับซ้อน การเปลี่ยนแปลงเหล่านี้จะส่งผลกระทบกับการเปลี่ยนแปลงที่เกิดขึ้นภายในฟังก์ชันที่ไม่ระบุตัวตนหรือแลมบ์ดาซึ่งในบางสถานการณ์ทั้งคู่จะพยายามที่จะ 'แปลง' โค้ดเป็นโครงสร้างอื่นซึ่งเข้ากันไม่ได้กับอีก
ด้วยเหตุนี้จึงถูกห้ามไม่ให้มีปฏิสัมพันธ์
วิธีบล็อก iterator ทำงานภายใต้ประทุนจัดการกับดีนี่
เป็นตัวอย่างง่ายๆของความไม่ลงรอยกัน:
public IList<T> GreaterThan<T>(T t)
{
IList<T> list = GetList<T>();
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item;
}
return items.ToList();
}
คอมไพเลอร์ต้องการแปลงสิ่งนี้ไปพร้อม ๆ กันเช่น:
private class Magic
{
private T t;
private IList<T> list;
private Magic(List<T> list, T t) { this.list = list; this.t = t;}
public IEnumerable<T> DoIt()
{
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item;
}
}
}
public IList<T> GreaterThan<T>(T t)
{
var magic = new Magic(GetList<T>(), t)
var items = magic.DoIt();
return items.ToList();
}
และในขณะเดียวกันแง่มุมของตัววนซ้ำก็พยายามทำเพื่อสร้างเครื่องสถานะเล็ก ๆ ตัวอย่างง่ายๆบางอย่างอาจใช้งานได้กับการตรวจสอบสภาพจิตใจในระดับที่เหมาะสม (ก่อนอื่นให้จัดการกับการปิดแบบซ้อนกัน (อาจเป็นไปได้โดยพลการ)) จากนั้นดูว่าคลาสผลลัพธ์ที่อยู่ในระดับล่างสุดสามารถเปลี่ยนเป็นเครื่องสถานะตัววนซ้ำได้หรือไม่
อย่างไรก็ตามสิ่งนี้จะเป็น
- งานค่อนข้างเยอะ.
- ไม่สามารถใช้งานได้ในทุกกรณีหากไม่มีอย่างน้อยที่สุดด้านบล็อกตัววนซ้ำที่สามารถป้องกันไม่ให้มุมมองการปิดใช้การแปลงบางอย่างเพื่อประสิทธิภาพ (เช่นการส่งเสริมตัวแปรในพื้นที่ให้เป็นตัวแปรอินสแตนซ์แทนที่จะเป็นคลาสการปิดที่มีคุณสมบัติครบถ้วน)
- หากมีโอกาสเกิดการทับซ้อนกันเล็กน้อยโดยที่เป็นไปไม่ได้หรือยากพอที่จะไม่นำไปใช้ปัญหาการสนับสนุนที่เกิดขึ้นน่าจะสูงเนื่องจากการเปลี่ยนแปลงที่ละเอียดอ่อนจะหายไปกับผู้ใช้จำนวนมาก
- สามารถแก้ไขได้ง่ายมาก
ในตัวอย่างของคุณเป็นดังนี้:
public IList<T> Find<T>(Expression<Func<T, bool>> expression)
where T : class, new()
{
return FindInner(expression).ToList();
}
private IEnumerable<T> FindInner<T>(Expression<Func<T, bool>> expression)
where T : class, new()
{
IList<T> list = GetList<T>();
var fun = expression.Compile();
foreach (var item in list)
if (fun.Invoke(item))
yield return item;
}
async
lambdas ที่ไม่ระบุตัวตนที่อนุญาตให้await
อยู่ใน C # 5.0 ได้แล้วฉันสนใจที่จะทราบว่าเหตุใดพวกเขาจึงยังไม่ได้ใช้ตัวทำซ้ำแบบไม่ระบุตัวตนyield
ภายใน ไม่มากก็น้อยมันเป็นเครื่องกำเนิดไฟฟ้าสถานะเดียวกัน