2010-04-12 7 views
7

저는 많은 Windows GUI 프로그래밍을하지 않기 때문에, WinForms에 익숙한 사람들에게 익숙하지 않을 수 있습니다. 불행히도 문제를 설명 할 수있는 리소스를 찾을 수 없었습니다. 오늘 디버깅하는 동안 발생했습니다.Control.EndInvoke는 예외를위한 호출 스택을 재설정합니다.

비동기 대리인에서 EndInvoke를 호출하는 경우 재 throw 된 메소드의 실행 중에 throw 된 예외가 발생합니다. 호출 스택에는 예외의 원래 소스가 반영됩니다.

그러나 Windows.Forms.Control에서 유사한 작업을 수행하면 Control.EndInvoke 구현이 호출 스택을 다시 설정합니다. 이것은 간단한 테스트 또는 반사경의 코드를 보면 알 수 있습니다. EndInvoke에서 관련 코드 발췌 여기에 있습니다 :

if (entry.exception != null) 
{ 
    throw entry.exception; 
} 

는 이해가 그 제어 및 비동기 대표에 EndInvoke이 다른/시작,하지만 난 Control.EndInvoke에 비슷한 행동을 기대했을 것이다.

원래 호출 스택을 보존하기 위해 비동기 대리자가 수행하는 작업이 Control에서 수행되지 않는 이유가 있습니까?

답변

1

실제 이유는 모르겠지만 비동기 대리자는 RPC와 비슷하지만 컨트롤 대리인은 Win32 메시지 전송을 기반으로 할 수 있습니다. 서로 다른 기술이므로이 기능의 영향은 동일하지 않을 수 있습니다. 비동기 델리게이트는 모든 원격 코드에서 이익을 얻습니다. 개발자는 다른 프로세스 나 컴퓨터간에 예외 호출 스택을 전송하는 코드를 작성하고 컨트롤 대리자는 동일한 프로세스 내에서 PostMessage를 사용하여 RPC를 시뮬레이션합니다. 다른 팀, 다른 코드.

1

또한 Control.EndInvoke은 프레임 워크의 몇 가지 Managed EndInvokes 중 하나입니다 (Reflector에서 코드를 볼 수 있음). 그들은 원래 스택을 던져 버리는 관리되지 않는 도우미가 있어야 할 것입니다.

는 사실, 그것은 단지이 EndInvoke 관리하는 생각하지만, IAsyncResult 매개 변수를 사용하여 다른 관리 End* 루틴이있다. 모든 것을 검사하지는 않았지만, 검토 한 모든 사람들이 예외를 던지거나 Stephen Cleary의 .NET 4의 GetWaiter.GetResult을 사용하는 방법을 효과적으로 사용합니다. 관리 및 관리되지 않는 헛소리로 스택은 예외를 위해 복원됩니다.

1

나는 컨트롤이 (아마 그냥 감독을)하지 않는 이유를 잘 모르겠지만, 당신은 UI 형태로 작업을 예약하여 .NET 4.0에서 그것을 해결할 수 있습니다

private BackgroundWorker bgw; 
    private TaskFactory uiTaskFactory; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     this.uiTaskFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 
     this.bgw = new BackgroundWorker(); 
     this.bgw.DoWork += bgw_DoWork; 
     this.bgw.RunWorkerAsync(); 
    } 

    void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     var task = this.uiTaskFactory.StartNew(this.OuterTaskFunction); 
     try 
     { 
      task.Wait(); 
     } 
     catch (Exception ex) 
     { 
      // Note: Full stack trace preserved 
      MessageBox.Show(ex.InnerException.ToString()); 
     } 
    } 

    void OuterTaskFunction() 
    { 
     this.InnerTaskFunction(); 
    } 

    void InnerTaskFunction() 
    { 
     throw new InvalidOperationException("Blah."); 
    } 
-3

I 당신의 메시지의 100 %를 읽지 않아서 이것이 도움이되는지 확실하지 않거나 확실한 것을 말하고 있습니다. 그러나 예외가 잡히고 쓸 때 당신은

"throw iAmAnCaughtExceptionInstance;"라고 쓰십시오. 호출 스택은 저장되지 않습니다

, 당신은 단지

은 "던질;"작성해야

다음 호출 스택이 저장됩니다.

+1

저는 알고 있습니다. 그러나 저는 Windows.Forms.Control을 구현 한 사람이 아니기 때문에 거의 도움이되지 않습니다. –

관련 문제