47

我正在尝试在一项任务上设置公寓状态,但看不到这样做的选择。有没有办法使用任务来做到这一点?

for (int i = 0; i < zom.Count; i++)
{
     Task t = Task.Factory.StartNew(zom[i].Process);
     t.Wait();
}
4

5 回答 5

100

失败时StartNew,您只需自己做:

public static Task<T> StartSTATask<T>(Func<T> func)
{
    var tcs = new TaskCompletionSource<T>();
    Thread thread = new Thread(() =>
    {
        try
        {
            tcs.SetResult(func());
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}

(您可以为其创建一个Task看起来几乎相同的选项,或者为其中的一些选项添加重载StartNew。)

于 2013-05-23T19:56:44.020 回答
19

Servy 启动 void 任务的答案超载

public static Task StartSTATask(Action func)
{
    var tcs = new TaskCompletionSource<object>();
    var thread = new Thread(() =>
    {
        try
        {
            func();
            tcs.SetResult(null);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}
于 2016-02-11T22:46:08.703 回答
13

例如,您可以按如下方式创建新任务:

       try
        {
            Task reportTask = Task.Factory.StartNew(
                () =>
                {
                    Report report = new Report(this._manager);
                    report.ExporterPDF();
                }
                , CancellationToken.None
                , TaskCreationOptions.None
                , TaskScheduler.FromCurrentSynchronizationContext()
                );

            reportTask.Wait();
        }
        catch (AggregateException ex)
        {
            foreach(var exception in ex.InnerExceptions)
            {
                throw ex.InnerException;
            }
        }
于 2013-06-20T14:29:30.830 回答
3

这是Task构造函数和RunSynchronously方法的一个很好的用例。

public static Task<T> RunSTATask<T>(Func<T> function)
{
    var task = new Task<T>(function, TaskCreationOptions.DenyChildAttach);
    var thread = new Thread(task.RunSynchronously);
    thread.IsBackground = true;
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return task;
}

的目的TaskCreationOptions.DenyChildAttach是使生成的任务的行为与 Servy 的解决方案相同(不可能将子任务附加到父任务TaskCompletionSource.Task)。拒绝孩子依附也是Task.Run方法的行为。

于 2020-06-08T23:53:39.263 回答
1

这是我在 Action 中使用的,因为我不需要返回任何东西:

public static class TaskUtil
{
    public static Task StartSTATask(Action action)
    {
        var tcs = new TaskCompletionSource<object>();
        var thread = new Thread(() =>
        {
            try
            {
                action();
                tcs.SetResult(new object());
            }
            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        return tcs.Task;
    }
}

我这样称呼它:

TaskUtil.StartSTATask(async () => await RefreshRecords());

有关详细信息,请参阅https://github.com/xunit/xunit/issues/103Func vs. Action vs. Predicate

仅供参考,这是我需要设置公寓状态的例外情况:

System.InvalidOperationException 发生 HResult=-2146233079
Message=调用线程必须是 STA,因为许多 UI 组件都需要这个。Source=PresentationCore StackTrace:在 System.Windows.Input.InputManager..ctor() 在 System.Windows.Input.InputManager.GetCurrentInputManagerImpl() 在 System.Windows.Input.Keyboard.ClearFocus()

于 2018-10-17T18:03:00.143 回答