2011-06-20 38 views
28

Trong C#, sử dụng .NET Framework 4, có cách nào thanh lịch để lặp lại cùng một hành động với số lần được xác định không? Ví dụ, thay vì:Có cách nào thanh lịch để lặp lại một hành động không?

int repeat = 10; 
for (int i = 0; i < repeat; i++) 
{ 
    Console.WriteLine("Hello World."); 
    this.DoSomeStuff(); 
} 

Tôi muốn viết một cái gì đó như:

Action toRepeat =() => 
{ 
    Console.WriteLine("Hello World."); 
    this.DoSomeStuff(); 
}; 

toRepeat.Repeat(10); 

hay:

Enumerable.Repeat(10,() => 
{ 
    Console.WriteLine("Hello World."); 
    this.DoSomeStuff(); 
}); 

Tôi biết tôi có thể tạo ra phương pháp mở rộng của riêng mình cho ví dụ đầu tiên , nhưng không phải là có một tính năng tồn tại mà làm cho nó đã có thể làm điều này?

Trả lời

22

Không có cách nào được tích hợp để thực hiện việc này.

Lý do là C# vì nó cố gắng thực thi phân chia giữa các mặt chức năng và mệnh lệnh của ngôn ngữ. C# chỉ làm cho nó dễ dàng để làm lập trình chức năng khi nó sẽ không tạo ra tác dụng phụ. Do đó, bạn có các phương pháp xử lý thao tác như LINQ's Where, Select, v.v., nhưng you do not get ForEach.

Theo cách tương tự, những gì bạn đang cố gắng làm ở đây là tìm một số cách chức năng để thể hiện bản chất là hành động bắt buộc. Mặc dù C# cung cấp cho bạn các công cụ để làm điều này, nhưng nó không cố gắng làm cho nó dễ dàng cho bạn, vì làm như vậy làm cho mã của bạn không rõ ràng và không thành ngữ.

Có một số , nhưng không phải là IEnumerable<T>.ForEach. Tôi sẽ nói sự tồn tại của là một tạo phẩm lịch sử xuất phát từ các nhà thiết kế khung không có suy nghĩ thông qua các vấn đề này trong khoảng thời gian .NET 2.0; nhu cầu phân chia rõ ràng chỉ trở nên rõ ràng trong 3.0.

+5

Tất nhiên, không có gì ngăn bạn viết phương thức 'lặp lại' hoặc' ForEach' của riêng mình trên IEnumerable - các nhà thiết kế ngôn ngữ đã rửa tay của họ trước thời điểm đó. – geofftnz

+0

Tôi có thể hỏi tại sao sử dụng 'ForEach' làm ví dụ hay không, đó có phải là một điều xấu không? – Coops

+1

@CodeBlend, điều đó sẽ tạo ra một câu hỏi hay. – Joe

26

Như thế này?

Enumerable.Range(0, 10).ForEach(arg => toRepeat()); 

Điều này sẽ thực hiện phương pháp của bạn 10 lần.

[Chỉnh sửa]

Tôi quá quen với việc có ForEach phương pháp khuyến nông trên Enumerable, mà tôi quên nó không phải là một phần của FCL.

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    foreach (var item in source) 
     action(item); 
} 

Đây là những gì bạn có thể làm mà không ForEach phương pháp khuyến nông:

Enumerable.Range(0, 10).ToList().ForEach(arg => toRepeat()); 

[Chỉnh sửa]

Tôi nghĩ rằng giải pháp thanh lịch nhất là thực hiện phương pháp tái sử dụng:

public static void RepeatAction(int repeatCount, Action action) 
{ 
    for (int i = 0; i < repeatCount; i++) 
     action(); 
} 

Cách sử dụng:

RepeatAction(10,() => { Console.WriteLine("Hello World."); }); 
+2

Câu trả lời cũ, nhưng bạn cũng có thể thực hiện 'Enumerable.Range (0, 10). Chọn (o =>/* trả lại hoặc làm gì đó * /)' –

+1

@ will-hart Điều đó thật bẩn và không rõ ràng trước nhìn thấy những gì bạn đang làm. Viết một phương pháp mở rộng tốt hơn là lạm dụng chọn để thực hiện một hành động. – Wolfsblvt

7

Nếu không tung ra phần mở rộng của riêng bạn, tôi đoán bạn có thể làm một cái gì đó như thế này

Action toRepeat =() => { 
     Console.WriteLine("Hello World."); 
     this.DoSomeStuff(); 
    }; 

    int repeat = 10; 
    Enumerable.Range(0, repeat).ToList().ForEach(i => toRepeat()); 
7

Đối với ngắn gọn của một liner bạn có thể làm điều này. Bạn không chắc chắn những gì bạn nghĩ ...

Enumerable.Repeat<Action>(() => 
{ 
    Console.WriteLine("Hello World."); 
    this.DoSomeStuff(); 
}, 10).ToList().ForEach(x => x()); 
+2

o nghĩ rằng đây không phải là thanh lịch. Điều này ít có thể đọc được và khó hiểu hơn là một tuyên bố đơn giản. – Ewerton

1
Table table = frame.AddTable(); 
int columnsCount = 7; 

Enumerable.Repeat<Func<Column>>(table.AddColumn, columnsCount) 
      .ToList() 
      .ForEach(addColumn => addColumn()); 
//or 
Enumerable.Range(0, columnsCount) 
      .ToList() 
      .ForEach(iteration => table.AddColumn()); 

các tùy chọn này không thanh lịch vì ToList(), nhưng cả hai đều làm việc trong trường hợp của tôi

0

Khai báo một phần mở rộng:

public static void Repeat(this Action action, int times){ 
    while (times-- > 0) 
     action.Invoke(); 
} 

Bạn có thể sử dụng phương thức tiện ích mở rộng là:

 new Action(() => 
        { 
         Console.WriteLine("Hello World."); 
         this.DoSomeStuff(); 
        }).Repeat(10); 
0
Enumerable.Repeat<Action>(() => { Console.WriteLine("Hello World"); this.DoSomething(); },10); 

thanh lịch phải không?

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