2010-02-12 3 views
11

우리는 비동기로 일부 작업을 수행하고 작업이 완료되면 이벤트를 발생시키는 방법을 사용하는 일반적인 시나리오가 있습니다.비동기 메서드를 동기화하는 일반적인 방법이 있습니까?

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

이 작업을 수행하는 도우미 메서드를 작성하는 방법이 있나요 :

우리가 기적 대신 우리는이 비슷한 모양의 코드가 그렇게 할 시간이있다? 나는 수행 할 Action을 전달할 수 있지만, 헬퍼 메소드가 EventHandler를 매개 변수로 전달할 수있는 것처럼 보이지 않기 때문에 어떤 이벤트를 듣는지 알 수있는 무언가를 전달하는 방법을 모르겠습니다.

이 바람직 반사 필요로하지 않는 솔루션

약간의 혼동이 될 것 같다

이 무엇 SomeObject의의 클래스의 샘플 것은 같은 것입니다 : 내가 당신의 표류를 잡을 경우

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

someobject의 구현 자입니까, 아니면 수정할 수없는 라이브러리 유형입니까? –

+0

그러나 우리는 그러한 대상이 많이 있습니다. 대부분의 작업에는 서버에 요청을 보내고 결과가 돌아 오기를 기다리는 것이 포함되므로 기본적으로 비동기가됩니다. – Davy8

+0

우리는 가장 일반적인 작업 중 하나 인 서버에서 객체 목록을 캐싱하는 방법을 사용하지만 정확한 객체 유형과 수신 대기하는 이벤트에 따라 다릅니다. 어떤 이벤트를 듣고 전달할 수 있기를 바란다. 그래서 중복되는 코드를 줄일 수있다. 유일한 차이점은 메서드와 완료시 발생하는 이벤트이기 때문이다. – Davy8

답변

4

비동기 작업을 수행하는 개체에 Asynchronous Design Pattern을 구현하는 것이 좋습니다.

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(); 
} 

이 패턴을 사용하면 객체에 대해 동시에 여러 비동기 작업을 수행 할 수 있습니다.

참고 : 웹에서 일반적인 AsyncResult 클래스의 구현을 쉽게 찾을 수 있습니다.

편집 :

모든 개체는 하나의 비동기 작업을 할 수 있다면, 현재의 디자인을 유지하려는 것처럼, 당신은 IAsyncOperation 인터페이스를 정의하고 모든 객체를 구현할 수 있습니다. 당신의 객체가 여러 비동기 작업을 포함 할 경우 반사하지 않고 당신이 원하는 것을 달성 할 수있는 방법이 없다 생각

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

을,하지만 당신은 여전히 ​​정의 할 수 있습니다 :

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

그런 다음 당신은 할 수 있습니다 ManualResetEvent를 래핑하는 모든 비동기 작업의 동기 버전입니다.

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

'someobject'의 클래스를 수정하지 않아도되는 해결책을 찾고 있습니다. 현재 패턴은 이미 수십 개의 클래스에 존재합니다. – Davy8

+0

더 나은 설명이 포함 된 편집 된 질문 – Davy8

+0

대답도 수정되었습니다. –

3

, 당신이 할 수있는 간단하게 다음과 같은 방법으로 대의원을 사용하면 전화 기능에 대한 가 대리자를 만들고,

public delegate string AsyncDelegate(); 

다음 전화 프록시 (SECURITY) 기능을 비활성화를 만들 수 있습니다 이 같은 이온 :

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

그게 전부, 당신은 그런 완료 또는 무언가 후에 실행하는 다른 함수 대리자를 추가하여 좀 더 복잡 할 수 있습니다 ..

즐기십시오!

+0

만약 내가 이미 동기식 기능을 가지고 있다고 가정하면 착각하지는 않습니까? 'someobject.PerformAsyncAction();을 호출하면 액션을 대기열에 넣고 곧바로 돌아옵니다. 내 함수를 메서드에 전달하면 액션이 실제로 완료 될 때 알 수 없습니다. – Davy8

+0

작업이 완료되면 ManualResetEvent를 '설정'하는 콜백을 호출합니다. main 함수는 ManualResetEvent가 'set'될 때까지 반환되지 않습니다. – Foole

+0

작업이 완료되면 어떻게 알 수 있습니까? 모든 동작 기능은 메시지를 보내고 즉시 반환합니다. – Davy8

관련 문제