C# async/await通过重新启动已经执行的代码表现得很奇怪

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) => {

我看到一些与async/Wait相关的奇怪行为,但我无法解释

以下是基本逻辑:

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