2012-05-17 33 views
6

Tôi có một lớp với hai phương thức, Load() và Process(). Tôi muốn có thể chạy các tác vụ nền riêng lẻ này hoặc theo thứ tự. Tôi thích cú pháp ContinueWith(), nhưng tôi không thể làm cho nó hoạt động được. Tôi phải thực hiện một tham số Task trên phương thức tôi tiếp tục và không thể có tham số Task trên phương thức ban đầu.Task.ContinueVới phương thức yêu cầu đối số nhiệm vụ?

Tôi muốn làm điều đó mà không có biểu thức lambda, nhưng tôi bị mắc kẹt hoặc sử dụng chúng, buộc một tham số nhiệm vụ trên một trong các phương pháp, hoặc tạo một phương thức thứ ba LoadAndProcess()?

void Run() 
{ 
    // doesn't work, but I'd like to do it 
    //Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodNoArguments); 

    Console.WriteLine("ContinueWith"); 
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodWithTaskArgument).Wait(); 

    Console.WriteLine("Lambda"); 
    Task.Factory.StartNew(() => { MethodNoArguments(); MethodNoArguments(); }).Wait(); 

    Console.WriteLine("ContinueWith Lambda"); 
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(x => { 
      MethodNoArguments(); 
     }).Wait(); 
} 

void MethodNoArguments() 
{ 
    Console.WriteLine("MethodNoArguments()"); 
} 

void MethodWithTaskArgument(Task t = null) 
{ 
    Console.WriteLine("MethodWithTaskArgument()"); 
} 
+1

Bạn có thể mô tả lý do tại sao bạn không muốn sử dụng biểu thức lambda? –

+0

Tôi không có lý do thực sự nào ngoài việc tôi thích cú pháp của ContinueWith và nghĩ rằng biểu thức lambda khiến nó trông ít bẩn hơn và khó hiểu hơn. –

+0

'Load' và' Process' có phụ thuộc vào nhau hay không? Dữ liệu được chia sẻ giữa chúng có đồng bộ hóa chủ đề có thể gặp sự cố không? –

Trả lời

12

Trong tất cả các quá tải của ContinueWith(), tham số đầu tiên là một đại biểu mà phải mất một Task, vì vậy bạn không thể vượt qua một đại biểu parameterless với nó.

Tôi nghĩ rằng việc sử dụng lambdas là hoàn toàn ổn và nó không làm tổn thương khả năng đọc. Và lambda trong mã của bạn là không cần thiết verbose:

Task.Factory.StartNew(MethodNoArguments).ContinueWith(_ => MethodNoArguments()) 

Hoặc, như Cory Carson đã chỉ ra trong một chú thích, bạn có thể viết một phương pháp khuyến nông:

public static Task ContinueWith(this Task task, Action action) 
{ 
    return task.ContinueWith(_ => action()); 
} 
4

Viết mã sạch khi bạn sử dụng nhiều continuations mà không phải là dễ dàng, mặc dù bạn có thể làm theo một vài quy tắc để làm cho mã sạch hơn:

  1. Sử dụng các hình thức ngắn hơn từ câu trả lời của svick
  2. Tránh chuỗi các sự tiếp tục. Lưu trữ kết quả của mỗi lần tiếp tục trong một biến riêng biệt và sau đó gọi ContinueWith trong một dòng riêng biệt
  3. Nếu mã tiếp tục dài, lưu trữ nó trong một biến lambda và sau đó ContinueWith lambda.
  4. Sử dụng phương thức tiện ích mở rộng như phương thức "Then" này để làm cho mã của bạn thậm chí còn sạch hơn.

Bạn có thể thay đổi mã của bạn để một cái gì đó như thế này, đó là hơi bụi:

 var call1=Task.Factory.StartNew(()=>MethodNoArguments()); 
     var call2 = call1.ContinueWith(_ => MethodNoArguments()); 
     call2.Wait(); 

hoặc thậm chí

 var call1 = Task.Factory.StartNew<Task>(MethodNoArguments); 
     var call2 = call1.Then(MethodNoArguments); 
     call2.Wait(); 

Stephen Toub thảo luận về Sau đó mở rộng và những cách khác bạn có thể dọn dẹp mã của bạn trong Processing Sequences of Asynchronous Operations with Tasks

Sự cố này được giải quyết cho tốt trong C# 4. Trong C# 5, bạn có thể sử dụng async/a chờ từ khóa để tạo mã sạch trông giống như phiên bản đồng bộ ban đầu, ví dụ:

static async Task Run() 
    { 
     await MethodNoArguments(); 
     await MethodNoArguments(); 
    } 

    static async Task MethodNoArguments() 
    { 
     await Task.Run(()=>Console.WriteLine("MethodNoArguments()")); 
    } 

Visual Studio 11 và .NET 4.5 có một giấy phép Go Live vì vậy bạn có thể bắt đầu sử dụng chúng ngay lập tức.

Bạn có thể sử dụng CTP không đồng bộ trong C# 4 để đạt được kết quả tương tự. Bạn có thể sử dụng Async CTP trong sản xuất vì nó có giấy phép hoạt động. Nhược điểm là bạn sẽ phải thực hiện một số thay đổi nhỏ cho mã của bạn khi bạn chuyển sang .NET 4.5 do sự khác biệt giữa CTP và .NET 4.5 (ví dụ: CTP có TaskEx.Run thay vì Task.Run).

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