2015-07-02 112 views
3

我已經閱讀了很多關於如何返回任務的值,但我似乎無法讓它在我的代碼上工作,仍然產生System.Threading.ThreadAbortExceptionC#任務返回輸出

嘗試使用Task.WaitAll即使這可能會阻止用戶界面,但無濟於事。

public DataTable GetResult(SomeVariable someVariable) { 
    // this do not work 
    //var task = Task<DataTable>.Factory.StartNew(() => 
    var task = Task.Factory.StartNew<DataTable>(() => 
    { 
     DataTable matchedData = new DataTable(); 
     matchedData = DoTask(someVariable); 
     return matchedData; 
    }, TaskCreationOptions.LongRunning); 
    try 
    { 
     var allTasks = new Task[] { task }; 
     Task.WaitAll(allTasks); 
     return task.Result as DataTable; 
    } 
    catch (ArgumentException) 
    { 
     throw; 
    } 
    catch (Exception) 
    { 
     // Always get the exception here: "A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll" 
     throw; 
    } 
} 

嘗試使用ContinueWhenAll但仍然相同。

public DataTable GetResultV2(SomeVariable someVariable) 
{ 
    queue = new Queue<Task>(); 
    DataTable matchedData = new DataTable(); 
    var task = Task.Factory.StartNew(() => 
    { 
     matchedData = DoTask(someVariable); 
     return matchedData; 
    }, TaskCreationOptions.LongRunning); 
    queue.Enqueue(task); 
    try 
    { 
     var done = Task.Factory.ContinueWhenAll(queue.ToArray(), completed => 
      { 
       return matchedData; 
      }); 
     return done.Result as DataTable; 
    } 
    catch (ArgumentException) 
    { 
     throw; 
    } 
    catch (Exception) 
    { 
     // Always get the exception here: "A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll" 
     throw; 
    } 
} 

DoTask僅僅是檢查和查詢數據庫的方法。

private DataTable DoTask(SomeVariable someVariable) 
{ 
    DataTable matchedData = new DataTable(); 
    // long database process/query 
    // populate and return matchedData 
    return matchedData; 
} 

編輯:參考如何/爲什麼它被使用。



    foreach (DataRow row in data.Rows) 
    { 
     string columnName = Convert.ToString(row["columnName"]); 
     string ProjectName = Convert.ToString(row["ProjectName"]); 
     string dbase_group = Convert.ToString(row["dbase_group"]); 
     string dbase_data = Convert.ToString(row["dbase_data"]); 
     var task = Task.Factory.StartNew(() => 
      { 
       SomeVariable someVariable = new SomeVariable(); 
       someVariable.DbName = dbase_group; 
       someVariable.columnName = columnName; 
       someVariable.ProjectName = ProjectName; 
       someVariable.TblName = dbase_data; 
       using (SearchProject search = new SearchProject()) 
       { 
        DataTable result = new DataTable(); 
        result = search.GetResult(SomeVariable); 
       } 
      }); 
     queue.Enqueue(task); 
    } 
    Task.Factory.ContinueWhenAll(queue.ToArray(), ant => 
    { 
     Console.WriteLine("Done with all tasks"); 
    }); 

+0

你爲什麼想在這種情況下使用任務? –

+0

請參閱上面的更新代碼。 – RaMa

+0

請將該代碼添加到原始文章中,以便格式正確,並且每個人都可以將其視爲問題的一部分。 –

回答

0

我認爲您應該採取步驟進行異步/等待。這會讓你的生活更輕鬆。

代碼中的某處您想要啓動多個任務並等待所有任務完成而不會阻止您的用戶界面。在你的例子中,這是GetResult。

您希望GetResult返回DataTable的對象。如果你想使用異步等待,你聲明函數調用getResult並返回一個任務,像這樣:

public async Task<DataTable> GetResultAsync(SomeVariable someVariable) {...} 

這是很常見的名字用字的異步函數異步末

在此功能中,您可以啓動任務,在這些任務正在運行時執行其他操作並等待任務完成。這個等待被稱爲「等待」。

您只能等待任務或任務對象,因此您需要等待返回任務的函數。

Task.WaitAll不返回任務,但無效。所以你不能等待Task.Waitall。

更好的是等待Task.WhenAll。該函數返回一個Task,因此你可以等待它。

public async Task<DataTable> GetResultAsync(SomeVariable someVariable) 
{ 
    var task = Task.Run(() => 
    { 
     DataTable matchedData = new DataTable(); 
     matchedData = DoTask(someVariable); 
     return matchedData; 
    } 
} 

如果你願意,你仍然可以使用Task.Factory.StartNew,請參閱MSDN進行討論,爲什麼他們現在更喜歡Task.Run

此功能將讓你一個結果。如果你想要調用if,你必須使調用者函數也是異步的,並讓它返回任務或任務。它的調用者也應該是異步等,直到你到達事件處理程序。這是唯一一個誰可以返回void:

private async void OnButton1_clicke(object Sender, ...) 
{ 
    try 
    { 
     await ProcessAllInputsAsync(...) 
    } 
    catch (ArgumentException exc) 
    { 
     ProcessArgumentException(...) 
    } 
    catch (Exception exc) 
    { 
     ProcessOtherException(...) 
    }   
} 

// first example: no parallel processing: 
private async Task ProcessAllInputsAsync(...) 
{ 
    foreach (SomeVariable someVariable in GetSomeVariables(...)) 
    { 
     DataTable dataTable = await GetResultAsync(...); 
     ProcessDataTable(dataTable); 
    } 
} 

// or do parallel processing: start several tasks and wait until all ready: 
private async Task ProcessAllInputsAsync(...) 
{ 
    List<Task<DataTable>> tasks = new List<Task<DataTable>>(); 
    foreach (SomeVariable someVariable in GetSomeVariables(...)) 
    { 
     tasks.Add(GetResultAsync(someVariable); 
    } 
    // all tasks are started, await for all to finish: 
    await Task.WhenAll(tasks.ToArray()); 
    // REMEMBER: you can only await for a Task or Task<T> 
    // Task.WhenAll returns a Task, so you can await for it 
    // Task.WaitAll returns void, so you can't await for it. 

    // now that all tasks are finished, get the results: 
    // Each Task<TResult> has the result in property Task.Result 
    // The result of a Task<TResult> is a TResult: 
    IEnumerable<TResult> fetchedDataTables = tasks.Select(task => task.Result); 

    // you can process it here if you want or do other things with it: 
    foreach (DataTabe fetchedDataTable in fetchedDataTables) 
    { 
     ProcessFetchedDataTable(fetchedDataTable); 
    } 
} 

見你擺脫了所有ContinueWith等東西。它由await取代,隨後是Task.Result中任務結果可用的下一個語句。

請注意:如果您執行任務。當所有等待的任務拋出異常時,您將收到一個AggregateException,其中由所有任務引發的所有異常都分組到屬性InnerExceptions中。所以,如果你想要的話,你可以捕捉到AggregateException並且通過所有的內部錯誤來看哪個任務拋出了哪些異常。