2015-07-02 75 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并且通过所有的内部错误来看哪个任务抛出了哪些异常。