2012-02-03 3 views
1
public void RefreshData() 
{ 
    // this is called on UI thread 

    List<ds> dataSource; 
    GetDsDelegate caller = GetDs; 
    caller.BeginInvoke(out dataSource, RefreshCallback, null); 
} 

private void RefreshCallback(IAsyncResult ar) 
{ 
    // this is called on worker thread 

    try 
    { 
     var result = (AsyncResult)ar; 
     var caller = (GetDsDelegate)result.AsyncDelegate; 

     List<ds> dataSource; 
     var success = caller.EndInvoke(out dataSource, ar); 

     if (success) 
     { 
      BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource); 
     } 
    } 
    catch 
    { 
     // NOTE: It's possible for this form to close after RefreshData is called 
     // but before GetDs returns thus the SetGridDataSource method no longer exists. 
     // Not catching this error causes the entire application to terminate. 
    } 

private void SetGridDataSource(List<ds> dataSource) 
{ 
    // this is called on UI thread 
    dataGrid.DataSource = dataSource; 
} 

RefreshData, RefreshCallback 및 SetGridDataSource는 모두 Windows Form 클래스의 메서드입니다. RefreshData를 호출하면 GetDsDelegate 대리자를 사용하여 GetDs 메서드가 호출됩니다. GetDs가 완료되면 RefreshCallback (별도의 스레드에 있음)이 호출됩니다. 마지막으로 SetGridDataSource가 호출되어 업데이트가 완료됩니다.누락 된 호출 된 메서드를 처리하는 방법

GetDs가 지연되고 양식이 닫히지 않는 한 모든 것이 제대로 작동합니다. GetDs가 완료되고 RefreshCallback을 호출하면 SetGridDataSource가 더 이상 존재하지 않습니다.

표시된 try/catch 블록 이외의 다른 조건을 처리하는 더 좋은 방법이 있습니까? 오류를 무시하는 대신 오류를 방지하는 것이 좋습니다. 더 나은 패턴을 사용할 수 있습니까?

편집

나는 오류가, 그것을 방지하기 위해 if (success && IsHandleCreated)-if (success)을 변경 명백 것으로 보이지만, 내가 뭔가 잘못하고, 또는 적어도 어색한 것 같은 여전히 ​​보인다 것처럼. 두 번째 BeginInvoke를 Invoke로 바꿀 수도 있으므로 EndInvoke는 필요하지 않습니다. 논리를 폼에서 옮기는 아이디어가 마음에 들지만 결과가 어떻게 변하는 지 알지 못합니다. 나는 BackgroundWorker도 같은 문제가 있다고 생각할 것이다. 그 콜백되고 더 이상 액세스 할 수 없습니다. 나는 사건이 결과로 제기 될 수 있다고 생각하지만, 그것은 약간 추상적으로 보인다. 조금 더 자세히 설명해 주시고 예를 들려 주시겠습니까?

+1

이 해결 못하는 경쟁 조건이다, 당신은 할 수 없습니다 모든 작업자 스레드가 실행을 마칠 때까지 양식을 닫을 수 있습니다. 이것은 BackgroundWorker로 훨씬 쉽게 수행 할 수 있습니다. –

답변

0

방법이 존재합니다. 양식이 닫힌 사실로 클래스 또는 메소드가 변경되지 않습니다. 정확한 예외를 게시하면 누군가가보다 정확한 도움을 제공 할 수 있습니다.

폼 또는 컨트롤 중 하나를 닫은 후 작업을 수행하려고했을 때 ObjectDisposedException이있는 것 같습니다.

그런 경우 로직을 향상시키고 SetGridDataSource를 호출하기 전에 양식이 닫혔는지 확인해야합니다.

그렇다면 디자인에 몇 가지 문제가있는 것으로 보입니다.

  1. 스레드 풀에서 SetGridDataSource를 호출하고 있지만 UI 스레드에서 호출해야합니다.
  2. 비동기 호출이 올바르게 연결되어 있지 않습니다. 특히 EndInvoke은 두 번째로 BeginInvoke입니다.
  3. 스레딩을 올바르게하는 데 도움이되는 좋은 방법은 BeginInvoke 호출을 연결하는 대신 BackgroundWorker과 같은 것을 사용하는 것입니다.
  4. 비즈니스 논리 (스레딩 및 비동기 논리 포함)를 UI 계층 및 양식에서 멀리 이동하는 것이 좋습니다.
  5. 예외 유형없이 catch을 수행하고 다시 throw하지 않고 무시한 예외를 처리하는 것은 매우 나쁜 생각입니다.당신은 내가 생각하는 다음을 수행 할 수
    BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource); 
    

    더 읽을 수 : 대신이 일의 방식으로

,

BeginInvoke(SetGridDataSource, dataSource); 
+0

.NET 4 컴파일러가 마지막 추론 예제를 지원합니까? .NET 3.5에서는 작동하지 않는다고 확신합니다. – Groo

+0

답장을 보내 주셔서 감사합니다. SetGridDataSource를 호출하면 Invoke 또는 BeginInvoke를 창 핸들을 만들 때까지 컨트롤에서 호출 할 수 없습니다. " 예외. 이것은 양식이 폐쇄 된 것을 감안할 때 나에게 의미가 있습니다. – rastro

관련 문제