C# 使用异步和等待

C# 使用异步和等待,c#,multithreading,asynchronous,task-parallel-library,C#,Multithreading,Asynchronous,Task Parallel Library,我想让这两个方法(1.DomainModel.Load(),2.UpdateEstate())一个接一个地运行在同一个线程上。不在UI线程上 如何执行此操作?请考虑以下代码: public async override void InitData() { _domainModel = new DomainModel() ProgressIndicatorViewModel.Start(); _State = Getstate();

我想让这两个方法(1.DomainModel.Load(),2.UpdateEstate())一个接一个地运行在同一个线程上。不在UI线程上


如何执行此操作?

请考虑以下代码:

    public async override void InitData()
    {
        _domainModel = new DomainModel()

        ProgressIndicatorViewModel.Start();
        _State = Getstate();
        await _domainModel.Load(_State, ProgressIndicatorViewModel); //returns a task
        ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
        ProgressIndicatorViewModel.Stop();

        DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
    }
DoOne不会在UI线程中执行

在客户端的大多数情况下,调用方线程是UI线程,因为大多数代码都是由用户操作(如鼠标单击)调用的,但这不是固定的行为

DoTwo将在一个单独的线程中执行,显然它不会在调用线程中执行

DoThree将在调用线程中执行

并且,DoFour将在UI线程上执行,调用线程是什么并不重要

所以@usr的评论是完全错误的

要实现目标,请按以下方式更改代码:

public async void Sample()
{
     DoOne();
     await DoTwo();
     DoThree();
     Dispather.BeginInvoke(() => DoFour());
}
我想使用这两种方法(1.domaminModel.Load(),2。 UpdateEstate())在同一线程上逐个运行。不在 用户界面线程

已更新,如果您只需要
\u domainModel.Load
ImageSelectionViewModel.UpdateState
在单独的非UI线程上运行,则只需执行以下操作:

public async override void InitData()
    {
        _domainModel = new DomainModel()

        ProgressIndicatorViewModel.Start();
        _State = Getstate();
        await Task.Factory.StartNew(() => {
             _domainModel.Load(_State, ProgressIndicatorViewModel).ContinueWith(() => {
             ImageSelectionViewModel.UpdateState(_State); }); 
           };
        ProgressIndicatorViewModel.Stop();

        DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
    }
注意,您不需要
DispatcherHelper.UIDispatcher.Invoke()
wrapper


如果希望
\u domainModel.Load
之后的
InitData
的其余部分在单独的线程上运行:

public async override void InitData()
{
    _domainModel = new DomainModel()

    ProgressIndicatorViewModel.Start();
    _State = Getstate();
    await Task.Run(async () =>
    { 
        await _domainModel.Load(_State, ProgressIndicatorViewModel))
        ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
    });
    ProgressIndicatorViewModel.Stop();

    ImageSelectionViewModel.RefreshImages(_imageList);
}
请注意,
Task.Run
将在此处自动为您的用户打开嵌套任务(属于
Task
)。另外,您可能需要在
Dispatcher.Invoke
中移动
ProgressIndicatorViewModel.Stop()

根据
\u domainModel.Load中的内容,您甚至可能不需要
任务。运行

public async override void InitData()
{
    _domainModel = new DomainModel()

    ProgressIndicatorViewModel.Start();
    _State = Getstate();
    await Task.Run(() => _domainModel.Load(_State, 
        ProgressIndicatorViewModel)).ConfigureAwait(false);
    ImageSelectionViewModel.UpdateState(_State); //returns void not a task!

    DispatcherHelper.UIDispatcher.Invoke(() =>
    {
        ProgressIndicatorViewModel.Stop();
        ImageSelectionViewModel.RefreshImages(_imageList)
    });
}

另一方面,您可能应该在
async void InitData
方法中处理异常。您将无法在it之外处理它们。

这不是问题的关键,但是
DispatcherHelper.UIDispatcher.Invoke
不是必需的,因为您已经在UI线程上。我很惊讶它居然会运行。需要它来刷新可观察的集合。别担心。运行perfactlyIs
UpdateState
async void
,与
InitData
相同?你有没有理由不使用
异步任务
?我已经编辑了你的标题。请参阅“”,其中一致意见是“不,他们不应该”。@nosestate不是异步的。只是一个更新不同ViewModel属性的函数我认为您的答案是错误的,因为您在同一个线程中执行以下行,[\u domainModel.Load]&[ImageSelectionViewModel.UpdateEstate]&[ProgressIndicatorViewModel.Stop],但他希望在同一个线程中有[\u domainModel.Load]&[ImageSelectionViewModel.UpdateEstate]。和ProgressIndicatorViewModel.Stop();应在调用方线程中调用。例如,如果UI线程是调用线程,而ProgressIndicatorViewModel.Stop()更改了UI,那么您的代码将无法成功执行。@YasserMoradi,您可能是对的,尽管我不明白为什么@Gilad需要
DispatcherHelper.UIDispatcher.Invoke
。我认为他希望在非UI线程上运行该方法的其余部分。我更新了答案以解决这两种情况。
注意,Task.Run将自动为您的此处展开嵌套的任务。
这是什么意思?这意味着如果lambda返回
任务,它将调用
Task.unwrap()
。您可以阅读有关它的内容。要使它按预期工作,您需要调用
Task.Factory.StartNew
的结果
Unwrap
。这是因为
ContinueWith
返回
Task
,因此
Task.Factory.StartNew
将返回
Task
,并且在当前版本中,您不必等待内部任务。@谢谢您的回复,请注意,我的答案是概念性的,它甚至不会生成!(:从概念上讲,我认为您需要在此处使用
await-await
或单个
await
Unwrap
,否则
await
之后的代码可能会在另一个线程上完成
UpdateState
之前继续。
await _domainModel.Load(_State, 
    ProgressIndicatorViewModel).ConfigureAwait(false);