2009-09-27 2 views
4

수정 : 실제 질문을 맨 위로 옮겼습니다.BeginInvoke 및 EndInvoke를 사용할 때 대리자를 전달/저장하지 않으려면 어떻게해야합니까?

업데이트 : 마지막에 몇 가지 코드가 추가 된 Microsoft의 사례를 찾아보십시오.

내 질문이 있습니다 :

  1. 는 BeginInvoke가 같은 대리자 인스턴스를 호출, 아니면 각 비행 메서드 호출에 대한 새 대리자 인스턴스를 구축해야 할 여러 전화 안전합니까?
  2. 각각에 대해 새 인스턴스를 만들어야하는 경우 IAsyncResult 값에서 원래의 대리자를 유지할 수있는 방법이 있습니까?
  3. 대리자를 사용하는 것보다 클래스에 비동기 지원을 추가하는 다른 방법이 있습니까?

자세한 정보는 다음과 같습니다.

내 클래스에 비동기 지원을 추가하고 있으며 간단하다고 생각했습니다.

이 클래스를 가지고 :

public class Calculator 
{ 
    public Int32 Add(Int32 a, Int32 b) 
    { 
     return a + b; 
    } 
} 

나는 단순히이 작업을 수행 할 수 있다고 생각 :이 작동하지 않습니다

public class Calculator 
{ 
    private delegate Int32 AddDelegate(Int32 a, Int32 b); 
    public Int32 Add(Int32 a, Int32 b) 
    { 
     return a + b; 
    } 

    public IAsyncResult BeginAdd(Int32 a, Int32 b, 
     AsyncCallback callback, Object obj) 
    { 
     return new AddDelegate(Add).BeginInvoke(a, b, callback, obj); 
    } 

    public Int32 EndAdd(IAsyncResult ar) 
    { 
     return new AddDelegate(Add).EndInvoke(ar); 
    } 
} 

, 두 가지 방법 각각 자신의 위임 객체와를 구성한다. EndInvoke 호출은 내가 호출 한 위임 인스턴스가 원래 BeginInvoke를 호출 한 인스턴스와 동일한 지 확인합니다.

그냥이 같은 변수에 대한 참조를 저장하는 것이 처리하는 간단한 방법 :

나는 동일한 클래스의 여러 인스턴스 메소드를 허용하는 데 문제가 완전히 알고 있어요
public class Calculator 
{ 
    private delegate Int32 AddDelegate(Int32 a, Int32 b); 
    private AddDelegate _Add; 

    public Calculator() 
    { 
     _Add = new AddDelegate(Add); 
    } 

    public Int32 Add(Int32 a, Int32 b) 
    { 
     return a + b; 
    } 

    public IAsyncResult BeginAdd(Int32 a, Int32 b, 
     AsyncCallback callback, Object obj) 
    { 
     return _Add.BeginInvoke(a, b, callback, obj); 
    } 

    public Int32 EndAdd(IAsyncResult ar) 
    { 
     return _Add.EndInvoke(ar); 
    } 
} 

주 등의 공유 상태와 관련하여, 동시에 실행


업데이트 : 나는 Asynchronous Delegates Programming Sample에 마이크로 소프트가 여기 예를 발견했다. 그것은 IAsyncResult 참조를 다시 AsyncResult 개체로 캐스팅하는 것을 보여줍니다. 그런 다음 AsyncDelegate 속성을 통해 원래의 위임 인스턴스를 얻을 수 있습니다.

안전한 방법입니까?

다른 말로하면 다음과 같은 등급입니까?

public class Calculator 
{ 
    private delegate Int32 AddDelegate(Int32 a, Int32 b); 

    public Int32 Add(Int32 a, Int32 b) 
    { 
     return a + b; 
    } 

    public IAsyncResult BeginAdd(Int32 a, Int32 b, AsyncCallback callback, Object obj) 
    { 
     return new AddDelegate(Add).BeginInvoke(a, b, callback, obj); 
    } 

    public Int32 EndAdd(IAsyncResult ar) 
    { 
     AddDelegate del = (AddDelegate)((AsyncResult)ar).AsyncDelegate; 
     return del.EndInvoke(ar); 
    } 
} 

답변

4

편집 : - 당신은 그냥 대리인 자체를 의미하는 경우에 당신이 다만 수 생각 :

public Int32 EndAdd(IAsyncResult ar) 
{ 
    var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate; 
    return d.EndInvoke(ar); 
} 

당신은 항상 대리자로를 캡처 할 수있다; 여기에 Async without the Pain과 같은 것을 입력하면 Action 콜백 (또는 Action<T>) 만 사용할 수 있습니다.

기타 일반적인 패턴에는 콜백 이벤트가 포함되며 아마도 ThreadPool.QueueUserWorkItem; IAsyncResult보다 훨씬 간단합니다.


using System; 
using System.Runtime.Remoting.Messaging; 
public class Calculator 
{ 
    private delegate Int32 AddDelegate(Int32 a, Int32 b); 
    public Int32 Add(Int32 a, Int32 b) 
    { 
     return a + b; 
    } 

    public IAsyncResult BeginAdd(Int32 a, Int32 b, 
     AsyncCallback callback, Object obj) 
    { 
     return new AddDelegate(Add).BeginInvoke(a, b, callback, obj); 
    } 

    public Int32 EndAdd(IAsyncResult ar) 
    { 
     var d = (AddDelegate)((AsyncResult)ar).AsyncDelegate; 
     return d.EndInvoke(ar); 
    } 
} 
static class Program 
{ 
    static void Main() 
    { 
     Calculator calc = new Calculator(); 
     int x = 1, y = 2; 
     Async.Run<int>(
      (ac,o)=>calc.BeginAdd(x,y,ac,o), 
      calc.EndAdd, result => 
      { 
       Console.WriteLine(result()); 
      }); 
     Console.ReadLine(); 
    } 
} 
static class Async 
{ 
    public static void Run<T>(
    Func<AsyncCallback, object, IAsyncResult> begin, 
    Func<IAsyncResult, T> end, 
    Action<Func<T>> callback) 
    { 
     begin(ar => 
     { 
      T result; 
      try 
      { 
       result = end(ar); // ensure end called 
       callback(() => result); 
      } 
      catch (Exception ex) 
      { 
       callback(() => { throw ex; }); 
      } 
     }, null); 
    } 
} 
+0

된 IAsyncResult 있도록 대의원의 지원이 내 요구에 자리 보이지만, I : 당신이 된 IAsyncResult를했으면 IAsyncResult를

의 특정 구현에 의존하지 않고 당신의 코드를 살펴 보겠습니다. 거기서 정의한 두 개의 정적 RunAsync 메서드는 동일한 매개 변수 목록을 가지므로 컴파일되지 않습니다. –

+0

좋아, 내가 쓰는 동안 AsyncResult를 통해 캐스트를 찾은 것 같아. 그럼 이렇게하는 것이 안전할까요? 반환 된 객체가 AsyncResult 객체가 아닌 위와 같은 상황이있을 수 없습니다. (일반적으로 delegate.BeginInvoke에서 일반적인 경우 IAsyncResult에 대해 묻지 않습니다.) –

+0

IAsyncResult의 특정 구현에 의존하지 않는 메서드에 대한 내 대답을 참조하십시오. – thecoop

2

난 항상 내가 BeginInvoke의 AsyncState의 일환으로 그것을라는 대리자 인스턴스를 저장 당신은 항상 그것을 얻을 수있는 방법은 : 여기에 발신자도 코드도 약 IAsyncResult 스트레스를받을 필요가 예입니다 나는 반환 된 값을 필요로

IAsyncResult ar; // this has your IAsyncResult from BeginInvoke in it 

MethodInvoker d = (MethodInvoker)ar.AsyncState; 
d.EndInvoke(ar); 
+0

즉, 콜백의 추가 매개 변수 기능을 잃어 버릴 것입니다. 저는 그 부분을 희생 할 수 있습니다. 지금 서로 다른 해결책을 비교해보기 만하면됩니다. –

+0

AsyncState에 다른 물건을 저장하려는 경우 [] 객체를 저장할 수 있습니다. – thecoop

관련 문제