2011-08-11 26 views
6

Tôi có một tác vụ không đồng bộ ngắn sẽ thường xuyên bị hủy sau khi đã bắt đầu. Lớp "Task" có một chỉ báo IsCanceled mà tôi nghĩ sẽ thuận tiện khi sử dụng để chỉ ra rằng tác vụ async đã bị hủy mà không chạy đến khi hoàn thành, nhưng theo như tôi có thể nói cách duy nhất để có một tác vụ async được đánh dấu là hủy để ném một TaskCanceledException trong hàm async. Thường xuyên ném một ngoại lệ, để chỉ ra một tình huống xảy ra không bình thường, đi ngược lại cách tôi hiểu ngoại lệ nên được sử dụng. Có ai biết một cách tốt hơn để chỉ ra một nhiệm vụ không đồng bộ được hủy bỏ khi nó dự kiến ​​sẽ xảy ra thường xuyên?C# async CTP - Làm thế nào để đánh dấu một tác vụ không đồng bộ như đã hủy mà không cần ném một TaskCanceledException?

tiếp theo tốt nhất thay thế của tôi là để trả về một cấu trúc có nó sở hữu IsCanceled riêng:

(Tôi đã bỏ qua một số mã hóa và phong cách thực hành tốt cho ngắn gọn ở đây)

class MightBeCanceled<T> 
{ 
    public readonly T Value; 
    public readonly bool IsCanceled; 

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; } 
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true); 
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; } 
} 

... 

static async Task<MightBeCanceled<int>> Foo() 
{ 
    if (someCancellationCondition) 
     return MightBeCanceled<int>.Canceled; 
    else 
     return new MightBeCanceled<int>(42); 
} 

static async void Bar() 
{ 
    var mightBeCanceled = await Foo(); 

    if (mightBeCanceled.IsCanceled) 
     ; // Take canceled action 
    else 
     ; // Take normal action 
} 

Nhưng điều này dường như dư thừa và khó sử dụng hơn. Chưa kể nó giới thiệu các vấn đề nhất quán bởi vì sẽ có hai IsCanceled (một trong Task và một trong MightBeCanceled).

+1

Ai đang hủy Foo? Nó chỉ có thể được hủy bởi người gọi, sử dụng một CancellationToken –

Trả lời

2

Vấn đề là ngoại lệ sẽ không được giám sát cho đến khi bạn chọn đợi. Vì vậy, các hành động gọi await có nghĩa là bạn cuối cùng sẽ quan sát ngoại lệ tại một số điểm khi giá trị cuối cùng được trả lại hoặc nếu bạn chờ đợi cho công việc để hoàn thành. Tuy nhiên, nếu bạn không bao giờ quan tâm (đó là một nhiệm vụ lửa và quên), thì ngoại lệ là một vấn đề không (đối với hầu hết các phần).

Tôi cũng vậy, hãy tìm một chút kỳ quặc này, luôn phải thử/nắm bắt nhiệm vụ xử lý các trường hợp ngoại lệ tổng hợp. Tuy nhiên, hãy nghĩ về điều này một chút:

try 
{ 
    var myResult = await Foo(); 

    // Do Success Actions Here... 
} 
catch(AggregateException e) 
{ 
    e.Flatten().Handle(ex => 
     { 
      if(ex is OperationCanceledException) 
      { 
       // Do Canceled Thing Here 
       return true; 
      } 

      return false; 
     }); 
} 

Nó không quá xa. Theo nhiều cách, tôi nghĩ đến việc hủy một nhiệm vụ khác và tôi sẽ làm như thế nào? ThreadAbortException? Nó không có vẻ cho đến nay lấy để chỉ đơn giản là ném một ngoại lệ cụ thể về hủy bỏ.

Đây là mẫu khá nhiều mà tôi đã thấy được ủng hộ ở nhiều nơi để xử lý việc hủy.

2

Thông thường mục đích hủy là dành cho người gọi hành động không đồng bộ để cho biết hành động mà nó sẽ ngừng xử lý. Đối với điều này, bạn vượt qua một CancellationToken vào phương pháp không đồng bộ. Đó là lý do tại sao chờ đợi một nhiệm vụ đặt IsCancelled ném chính nó. Nó có nghĩa là một tín hiệu đặc biệt cho một hành động khiêu khích bên ngoài. Không được sử dụng Hủy tác vụ cho luồng điều khiển, nhưng chỉ để đưa ra hành động không đồng bộ, tùy chọn kết thúc sớm nếu bên đang chờ báo hiệu rằng nó không còn muốn kết quả nữa.

Nếu hành động không đồng bộ bị hủy trong nội bộ, bạn đã quá tải khái niệm và tôi cho rằng phản ánh sự khác biệt trong hủy là đáng giá và phải là thuộc tính trên vùng chứa kết quả tương tự như cách bạn đề xuất. Nhưng thay vì gọi nó là MightBeCancelled<T>, có thể giống như InternallyCancellableResult<T>, để phản ánh sự khác biệt của các khái niệm hủy.

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