2009-03-20 27 views
6

Giả sử tôi có một số mã mà trông như thế này:C# Mã Đơn giản hóa truy vấn: tuần tự Foreach Loops

foreach(type x in list y) 
{ 
    //dostuff1(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff2(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff3(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff4(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff5(x) 
} 

tôi không thể kết hợp mọi thứ vào cái lớn cho vòng lặp như thế này:

foreach (type x in list y) 
{ 
    //dostuff1(x) 
    //dostuff2(x) 
    //dostuff3(x) 
    //dostuff4(x) 
    //dostuff5(x) 
} 

Làm như vậy sẽ thay đổi thứ tự. Bất kỳ bình luận nào về cách tốt nhất để làm cho mã đơn giản hơn trong C#?

Tôi tưởng tượng tôi có thể giải quyết vấn đề này bằng cách tạo một hàm như thế này, mặc dù tôi thà để nó cách nó là hơn buộc độc giả tương lai của mã của tôi để hiểu yield:

void func(type x) 
{ 
    dostuff1(x) 
    yield 0; 
    dostuff2(x) 
    yield 0; 
    dostuff3(x) 
    yield 0; 
    dostuff4(x) 
    yield 0; 
    dostuff5(x) 
    yield break; 
} 

for (int i = 0; i<5; ++i) 
{ 
    foreach (type x in list y) 
    { 
     //Call func(x) using yield semantics, which I'm not going to look up right now 
    } 
} 

Trả lời

30

Một lựa chọn khác:

List<Action<Foo>> actions = new List<Action<Foo>> { 
    doStuff1, doStuff2, doStuff3, doStuff4, doStuff5 
}; 

foreach (Action<Foo> action in actions) 
{ 
    foreach (Foo x in list) 
    { 
     action(x); 
    } 
} 

Chỉ cần chọn và hoạt động. Ví dụ:

using System; 
using System.Collections.Generic; 

public class Test 
{ 
    static void Main(string[] args) 
    { 
     var actions = new List<Action<string>> { 
      First, Second 
     }; 

     foreach (var action in actions) 
     { 
      foreach (string arg in args) 
      { 
       action(arg); 
      } 
     } 
    } 

    static void First(string x) 
    { 
     Console.WriteLine("First: " + x); 
    } 

    static void Second(string x) 
    { 
     Console.WriteLine("Second: " + x); 
    } 
} 

Kết quả chạy Test.exe a b c

First: a 
First: b 
First: c 
Second: a 
Second: b 
Second: c 
+0

+1 - Các đại biểu là đẹp hơn rất nhiều trong C# hơn trong VB.NET :( –

2

Làm thế nào về:

interface IDoStuff 
{ 
    void DoStuff(x); 
} 

List<IDoStuff> listOfActions = ... 
foreach (IDoStuff iDoStuff in listOfActions) 
{ 
    foreach (type x in list y) 
    { 
     iDoStuff(x); 
    } 
} 

[sửa] Và có, bạn thay vì nên đi cho các giải pháp chung chung như J. Skeet nói (mặc dù bạn có thể sử dụng một giao diện chung thay vì một đại biểu là tốt).

+0

Tại sao sử dụng một giao diện khi đại biểu rất tiện lợi hơn? :) –

+0

Bạn nói đúng ..Nhưng đôi khi tôi thích chúng khi tôi cần kết hợp một số trạng thái với hành động, chỉ để đóng gói từng hành động + dữ liệu trong một lớp riêng biệt (không phải bạn cũng không thể chuyển một đại biểu công khai khác từ một lớp khác). nên được sử dụng trong những trường hợp đó? – Groo

+0

Có một vài lợi ích cho các đại biểu ở đây: 1) Bạn có thể sử dụng các biểu thức lambda và các phương thức ẩn danh (cung cấp hỗ trợ đóng cửa - liên kết trạng thái!) 2) Bạn có thể có nhiều cá thể ủy nhiệm từ cùng một lớp - ít lộn xộn hơn nhiều so với một lớp cho mỗi giao diện thực hiện. –

0

Nếu bạn phải giữ nguyên bản chất tuần tự, bạn không thể làm được gì nhiều. Bạn có thể thực hiện một số phím tắt của phương thức mở rộng, nhưng IMHO điều này làm cho mã ít đọc được hơn. Ngoài ra, bạn có thể gặp sự cố tùy thuộc vào chữ ký của phương thức.

Bạn có thể cấu trúc lại để di chuyển lặp lại đến các hàm riêng biệt.

// Method 1 
DoStuff1ToList(y); 
DoStuff2ToList(y); 
DoStuff3ToList(y); 
DoStuff4ToList(y); 
DoStuff5ToList(y); 

// Do Stuff 1 
foreach (var x in y) 
{ 
    // do actual stuff 
} 
5

Nếu bạn có một danh sách tương đối ổn định các hành động, bạn chỉ có thể tránh các vòng foreach, nhưng vẫn làm những hành động một cách rõ ràng (chưa được thử nghiệm mã):

list.ForEach(action1); 
list.ForEach(action2); 
list.ForEach(action3); 
list.ForEach(action4); 
0

tôi nghĩ rằng đây giống như testing.ForEach (hành động) vì vậy chỉ cần sử dụng nếu bạn đi xuống loại tuyến đường này.

private static void DoDifferentStuffToThings() 
    { 
     List<string> testing = new List<string>() { "hello", "world" }; 

     Action<string> action1 = (a) => 
     { 
      Console.WriteLine("Action 1 {0}", a); 
     }; 

     Action<string> action2 = (a) => 
     { 
      Console.WriteLine("Action 2 {0}", a); 
     }; 

     DoStuffToThings<string>(testing, action1); 
     DoStuffToThings<string>(testing, action2); 
    } 

    private static void DoStuffToThings<T>(IEnumerable<T> list, Action<T> dothing) 
     where T : class 
    { 
     foreach (var item in list) 
     { 
      dothing(item); 
     } 
    } 
5

Câu trả lời của Jon Skeet là tuyệt vời (tôi vừa bỏ phiếu). Đây là một ý tưởng để thực hiện thêm một bước nữa:

Nếu bạn làm điều này rất nhiều, bạn có thể tạo một phương thức mở rộng có tên "DoActionsInOrder" (hoặc có thể bạn có tên tốt hơn). Dưới đây là ý tưởng:

public static void DoActionsInOrder<T>(this IEnumerable<T> stream, params Action<T> actionList) 
{ 
    foreach(var action in actionList) 
    { 
      foreach(var item in stream) 
      { 
       action(item); 
      } 
    } 
} 

Sau đó, bạn có thể gọi nó như thế này:

myList.DoActionsInOrder(doStuff1, doStuff2, doStuff3, doStuff4, doStuff5); 
+0

đồng bộ chết tiệt! Tôi vừa hoàn thành chính xác phương pháp mở rộng. Sự khác biệt duy nhất tôi có thể thấy là bạn sử dụng var thay vì T :) +1, sau đó! – flq

+0

:) Cảm ơn. Thật tuyệt vời khi trang web này khiến chúng tôi kêu gọi trả lời các câu hỏi của người khác nhanh nhất có thể! Tôi có thể bị nghiện! –

Các vấn đề liên quan