异常未被上抛。

7
我试图捕获一个抛出的异常,但它没有冒泡到调用它的地方。在InsertNewUser的catch块中出现错误,显示:

"An exception of type 'System.Exception' occurred in PeakPOS.exe but was not handled in user code"

如果我点击继续调试,它会跳转到一个名为App.g.i.cs的文件,并在我不理解但与打断点有关的行上停止运行。之后应用程序就会终止。

把异常重新抛出并再次捕获并处理(即将被处理),那么为什么它说这个异常没有被处理呢?


AccessViewModel.cs

public void SaveNewUser(Popup popup)
{
    UserAccounts.Add(TempUser);

    string salt = PeakCrypto.GenerateSalt();
    string hash = PeakCrypto.GenerateHashedPassword(Password + salt);
    try
    {
        PeakDB.InsertNewUser(TempUser, salt, hash);
    }
    catch (Exception e)
    {
        //TODO notify user that new account could not be saved
    }

    CreateNewAccount();

    if (popup != null)
        popup.IsOpen = false;
}

PeakDB.cs

public static async void InsertNewUser(UserAccount user, String salt, String hash)
{
    var db = await DatabaseHelper.GetDatabaseAsync();

    try
    {
        using (var userStatement = await db.PrepareStatementAsync(
            "INSERT INTO AccessAccounts (FirstName, LastName, Salt, Hash) VALUES(@first, @last, @salt, @hash)"))
        {
            userStatement.BindTextParameterWithName("@first", user.FirstName);
            userStatement.BindTextParameterWithName("@last", user.LastName);
            userStatement.BindTextParameterWithName("@salt", salt);
            userStatement.BindTextParameterWithName("@hash", hash);
            await userStatement.StepAsync();
        }
    }
    catch(Exception e)
    {
        // TODO: log the exception error
        throw;
    }
}

App.g.i.cs

#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
    UnhandledException += (sender, e) =>
    {
        if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
    };
#endif

你尝试过取消勾选“发生异常时中断”复选框并重新运行吗?我认为在调试模式下它会在异常处中断。 - Saagar Elias Jacky
@Saagar:是的。发生的情况是它进入了App.g.i.cs文件,并在if语句处中断,就像以前一样,只是不再在catch中中断。我想知道我是否误解了try/catch。捕获异常并不意味着处理它吗? - ShrimpCrackers
2个回答

6

这是 async 操作的预期行为。你的代码处理/捕获了方法同步部分抛出的异常,但让应用程序处理异步部分。

如果你在 InsertNewUser 方法的第一行(同步部分)明确抛出异常,则可以观察到你期望的行为。

修复方法:正确使用 await 你的 async 方法。

// must return at least `Task` to be awaitable
public static async Task InsertNewUser(...

然后使用await方法(注意,“async是病毒性的” - 异步/等待最佳实践):

   try
   {
        await PeakDB.InsertNewUser(TempUser, salt, hash);
    }
    catch (Exception e) ...

或者至少在控制台应用程序中使用.Wait(WPF / WinForm / Asp.Net会死锁 - await vs Task.Wait-死锁?):

   try
   {
        PeakDB.InsertNewUser(TempUser, salt, hash).Wait();
    }
    catch (Exception e) ...

如果你两个都做不到,至少要使用正确的async委托和"旧异步委托"来调用async void方法。
注意:async void是不良实践,只应在表单事件中使用。

谢谢,Alexei。它起作用了。感谢您提供的链接,因为我是C#的新手,只是简单地浏览了异步/等待功能,并且并不是很理解。 - ShrimpCrackers
@ShrimpCrackers 欢迎。如果您需要使用 async/await,我强烈建议在进行任何严肃的工作之前先浏览 Stephen Cleary 的顶级答案。 - Alexei Levenkov

1

我遇到了一个问题,我的异常会挂起,但这是因为我正在使用await调用Web服务。我的解决方法是应用...

.ConfigureAwait(continueOnCapturedContext: false)

现在当我的内部网络服务产生异常时,我按预期收到了该异常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接