2010-02-12 52 views
11

Chúng tôi có kịch bản phổ biến này, nơi chúng tôi có một phương pháp thực hiện một số hành động asyncronously và đặt ra một sự kiện khi nó được thực hiện.Có cách nào chung để đồng bộ hóa một phương pháp không đồng bộ không?

Có những lúc mà chúng tôi muốn nó được thực hiện đồng bộ thay vì vậy chúng tôi có mã trông tương tự như sau:

ManualResetEvent reset = new ManualResetEvent(false); 
someobject.AsyncActionDone += (sender, args) => reset.Set(); 
someobject.PerformAsyncAction(); 
reset.WaitOne(); 

Có cách nào để viết một phương pháp helper để làm điều này? Tôi có thể vượt qua trong Action để thực hiện, nhưng tôi không chắc chắn làm thế nào để vượt qua một cái gì đó cho phép phương thức trợ giúp biết sự kiện nào để nghe vì nó không giống như bạn có thể truyền vào một EventHandler như một tham số.

Tốt một giải pháp mà không đòi hỏi phản ánh

Dường như có một số nhầm lẫn, đây là một mẫu của những gì SomeObject của lớp cũng giống như:

public class SomeClass 
{ 
    private ExternalServer someServerOverTheNetwork = new ExternalServer(); 

    public event EventHandler AsyncActionDone; 
    public Data SomeData { get; set; } 
    public void PerformAsyncAction() 
    { 
     someServerOverTheNetwork.GetSomeData(OnDataRetrived); 
    } 

    public Data OnDataRetrived(Data someData) 
    { 
     AsyncActionDone(this, new DataEventArgs(someData)); 
    } 
} 
+0

Bạn có phải là người triển khai của someobject hoặc là loại thư viện không thể sửa đổi được không? –

+0

Tuy nhiên, có rất nhiều đối tượng như vậy. Hầu hết các hành động liên quan đến việc gửi một yêu cầu đến một máy chủ và chờ kết quả để lấy lại, do đó tại sao chúng không đồng bộ theo mặc định. – Davy8

+0

Chúng ta có một phương pháp để thực hiện điều này cho một trong những hành động phổ biến nhất của chúng ta, lưu trữ một danh sách các đối tượng từ máy chủ, tuy nhiên điều đó phụ thuộc vào việc biết loại đối tượng chính xác và sự kiện cần nghe. Tôi muốn để có thể vượt qua trong đó sự kiện để lắng nghe để chúng tôi có thể làm giảm mã trùng lặp, vì những điều duy nhất khác nhau là phương pháp và sự kiện được nâng lên sau khi hoàn thành. – Davy8

Trả lời

4

Tôi sẽ xem xét triển khai Asynchronous Design Pattern trong các đối tượng thực hiện thao tác không đồng bộ.

public object Operation(object arg) 
{ 
    var ar = BeginOperation(arg, null, null); 

    return EndOperation(ar); 
} 

public IAsyncResult BeginOperation(object arg, AsyncCallback asyncCallback, object state) 
{ 
    AsyncResult asyncResult = new AsyncResult(asyncCallback, state); 

    // Lauch the asynchronous operation 

    return asyncResult; 
} 

private void LaunchOperation(AsyncResult asyncResult) 
{ 
    // Do something asynchronously and call OnOperationFinished when finished 
} 

private void OnOperationFinished(AsyncResult asyncResult, object result) 
{ 
    asyncResult.Complete(result); 
} 


public object EndOperation(IAsyncResult asyncResult) 
{ 
    AsyncResult ar = (AsyncResult)asyncResult; 

    return ar.EndInvoke(); 
} 

Với mẫu này, bạn có thể linh hoạt đồng thời nhiều thao tác không đồng bộ trên đối tượng của mình.

Lưu ý: Bạn có thể dễ dàng tìm thấy triển khai lớp AsyncResult chung trên web.

Edit:

Như bạn muốn giữ lại các thiết kế hiện nay, nếu tất cả các đối tượng của bạn chỉ có thể có một hoạt động không đồng bộ, sau đó bạn có thể định nghĩa một giao diện IAsyncOperation và thực hiện nó trong tất cả các đối tượng của bạn.

public interface IAsyncOperation 
{ 
    event EventHandler AsyncActionDone; 
    void PerformAsyncAction(); 
} 

Sau đó, bạn có thể có:

public static CallSynchronously(IAsyncOperation asyncOperation) 
{ 
    ManualResetEvent reset = new ManualResetEvent(false); 
    asyncOperation.AsyncActionDone += (sender, args) => reset.Set(); 
    asyncOperation.PerformAsyncAction(); 
    reset.WaitOne(); 
} 

Nếu đối tượng của bạn có thể chứa nhiều hoạt động không đồng bộ, sau đó mà không suy nghĩ Tôi nghĩ rằng không có cách nào để đạt được những gì bạn muốn làm, nhưng bạn vẫn có thể xác định một phiên bản đồng bộ của tất cả các hoạt động không đồng bộ kết thúc tốt đẹp ManualResetEvent.

public void PerformAction() 
{ 
    ManualResetEvent reset = new ManualResetEvent(false); 
    this.AsyncActionDone += (sender, args) => reset.Set(); 
    this.PerformAsyncAction(); 
    reset.WaitOne(); 
} 
+0

Tôi đang chụp một giải pháp không liên quan đến việc sửa đổi lớp 'someobject' Mẫu hiện tại tồn tại trong hàng tá lớp trong hệ thống của chúng tôi. – Davy8

+0

Câu hỏi đã chỉnh sửa với hy vọng một cách giải thích tốt hơn – Davy8

+0

Đã chỉnh sửa câu trả lời –

3

Nếu tôi bắt trôi dạt của bạn, bạn có thể chỉ cần sử dụng các đại biểu theo cách sau, tạo ra một đại biểu cho bạn chức năng cuộc gọi, cho phép gọi nó là

public delegate string AsyncDelegate(); 

sau đó, tạo một funct Proxy ion như thế này:

public static void ExecuteSync(AsyncDelegate func) 
    { 
     ManualResetEvent reset = new ManualResetEvent(false); 
     int threadId; 
     func.BeginInvoke((a)=>reset.Set(), null); 
     reset.WaitOne(); 
    } 

Thats tất cả, bạn có thể làm cho nó phức tạp hơn một chút bằng cách thêm một chức năng đại biểu để chạy sau khi hoàn thành hoặc một cái gì đó như thế ..

Thưởng thức!

+0

Nếu tôi không nhầm là giả sử bạn đã có một chức năng đồng bộ phải không? Khi tôi gọi 'someobject.PerformAsyncAction();' nó xếp hàng lên hành động và trả về ngay lập tức, tôi không thấy nếu tôi chuyển hàm của tôi sang phương thức của bạn, nó sẽ biết khi nào hành động thực sự được thực hiện. – Davy8

+0

Khi hành động hoàn thành, nó gọi hàm gọi lại là 'đặt' ManualResetEvent. Chức năng chính sẽ không trở lại cho đến khi ManualResetEvent được 'thiết lập'. – Foole

+0

Làm cách nào để biết khi nào hành động hoàn tất? Tất cả các chức năng hành động làm là gửi một tin nhắn và sau đó trả về ngay lập tức. – Davy8

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