C# async/await通过重新启动已经执行的代码表现得很奇怪
我看到一些与async/Wait相关的奇怪行为,但我无法解释 以下是基本逻辑:C# async/await通过重新启动已经执行的代码表现得很奇怪,c#,uwp,async-await,C#,Uwp,Async Await,我看到一些与async/Wait相关的奇怪行为,但我无法解释 以下是基本逻辑: public async Task Init(UI.INavigable NavigateFrom) <-- Starts from here { await NavigateFrom.Navigate<UI.Pages.Page>(await Common.CreateDrillInNavigationTransitionInfo(), async (Page) => {
public async Task Init(UI.INavigable NavigateFrom) <-- Starts from here
{
await NavigateFrom.Navigate<UI.Pages.Page>(await Common.CreateDrillInNavigationTransitionInfo(), async (Page) =>
{
// ...
m_SelectPage.OnCategorySelected += OnCategorySelected;
// ... (including more awaits)
await OnModelUpdated();
return Page;
});
}
private async Task OnModelUpdated()
{
await m_SelectPage.DataUpdated(...);
}
public async Task DataUpdated(...)
{
try
{
m_Initializing = true;
await Common.RunUiTask(async () =>
{
// ... (including more awaits)
await Task.Run(async () =>
{
// ... (including more awaits)
System.Diagnostics.Debug.Print("DataUpdated: Calling CategorySelected\n");
await OnCategorySelected(await GetSelectedCategory());
});
});
}
finally
{
m_Initializing = false;
}
}
private async Task OnCategorySelected(Model.Category Category)
{
Debug.Print("OnCategorySelected start\n");
var Adaptor = new Model.Adaptor(...);
var p = new InfoPage(m_ActualApp, Adaptor);
Debug.Print("OnCategorySelected navigate\n");
await p.Init(SelectPage);
Debug.Print("OnCategorySelected end\n");
}
public async Task Init(UI.INavigable NavigateFrom)
{
Debug.Print("Init start\n");
await NavigateFrom.Navigate<UI.Pages.InfoPage>(await Common.CreateDrillInNavigationTransitionInfo(), async (Page) =>
{
Debug.Print("Init lambda\n");
// ...
Debug.Print("Init lambda update\n");
await m_InfoPage.Updated(...);
Debug.Print("Init lambda end\n");
return Page;
});
Debug.Print("Init end\n");
}
从输出中可以清楚地看到,似乎只要它在Init函数中点击wait,或者在Init函数中的lambda中点击wait,它就会暂停正确的操作,然后在OnCategorySelected函数中重新启动,没有明显的原因
我无法解释发生了什么事。它应该只发生一次,因为没有代码再次调用OnCategorySelected。有什么想法吗
为了便于参考,我使用了以下实用程序函数,以防其中有些奇怪之处:
public static async Task<DrillInNavigationTransitionInfo> CreateDrillInNavigationTransitionInfo()
{
return await Common.RunUiTask(async () =>
{
return await Task.FromResult(new DrillInNavigationTransitionInfo());
});
}
public static class Common
{
public static async Task<T> RunUiTask<T>(Func<Task<T>> F)
{
return await CoreApplication.MainView.CoreWindow.Dispatcher.RunTaskAsync(async () =>
{
return await F();
});
}
}
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher Dispatcher, CoreDispatcherPriority Priority, Func<Task<T>> Func)
{
var TaskCompletionSource = new TaskCompletionSource<T>();
await Dispatcher.RunAsync(Priority, async () =>
{
try
{
var R = await Func();
TaskCompletionSource.SetResult(R);
}
catch (Exception ex)
{
TaskCompletionSource.SetException(ex);
}
});
return await TaskCompletionSource.Task;
}
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher Dispatcher, Func<Task<T>> Func)
{
return await RunTaskAsync(Dispatcher, CoreDispatcherPriority.Normal, Func);
}
}
如我所见,一切都很好。异步的意思是异步,如果你不知道的话。您调用了OnCategorySelected三次,并且完成了三次,您可以在您的日志中看到这一点。如果您需要异步,但有时需要同步完成,那么可以使用信号量LIM
SemaphoreSlim sl = new SemaphoreSlim(1, 1);
//some async code
await sl.WaitAsync();
//some sync code
sl.Release();
//again async code
我甚至看不到调用OnCategorySelected一次的代码。。。或者是谁提出了这个事件,或者它与什么有关。我猜这是你无法控制的好吧,它总是在大量代码和最少的示例之间进行权衡。我不认为调用函数的代码是必要的,因为问题的根源似乎就在这里,但我更新了我的原始帖子,添加了一些调用OnCategorySelected函数的代码。我还添加了打印到每个可能的函数调用,结果只有一个。只订阅一次事件,也考虑取消订阅。谢谢。我想这就成功了。我真的必须控制逻辑类的生存时间,并适当地取消订阅事件。我被调试器的行为弄糊涂了。哦,看起来我没有从你的问题中读到一些重要的信息。我很抱歉。当第二次调用OnCategorySelected时,您是否尝试放置断点并监视调用堆栈?
SemaphoreSlim sl = new SemaphoreSlim(1, 1);
//some async code
await sl.WaitAsync();
//some sync code
sl.Release();
//again async code