You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步方法中显式捕获NullReferenceException未生效问题咨询

异常无法捕获的核心原因

1. try块未覆盖所有可能抛异常的代码

你当前的try/catch仅包裹了await task.ConfigureAwait(false)这一段逻辑,以下风险代码完全在try块覆盖范围外,一旦触发NullReferenceException会直接逃逸:

  • 方法开头的Analytics.TrackEvent调用
  • 方法开头的((MainActivity)Activity).DisplayLoadingMessage(true, ...)调用
  • finally块执行结束后,冗余的((MainActivity)Activity).DisplayLoadingMessage(false)调用

这类场景大多发生在Fragment已和Activity解绑(比如用户触发搜索后立刻关闭页面、切走Fragment),此时Activity属性为null,强制转换或调用实例方法就会触发空引用异常,不会被你内部的catch捕获。

2. 后台线程调用UI方法导致异常脱离Task上下文

你在Task.Run的委托中使用了await SearchLeast(...).ConfigureAwait(false),ConfigureAwait(false)会让await之后的代码运行在线程池上下文,而非原UI同步上下文。此时你直接调用((MainActivity)Activity).ShowSearchResults(textResult)这类UI相关方法:
如果方法内部操作UI控件,Android要么直接抛线程访问异常,要么内部通过SyncContext.Post把逻辑投递到UI线程执行,投递的委托抛出的异常完全脱离你创建的Task的生命周期,自然无法被await task外层的try/catch捕获,和你提供的异常栈中SyncContext+<>c__DisplayClass2_0.<Post>b__0 ()的报错路径完全吻合。

3. 异步调用链的上下文逃逸

如果触发方法的点击事件回调是async void类型(Android端点击事件异步处理的常用写法),即使你方法内部捕获了大部分异常,一旦有未处理异常逃逸到异步方法构建器,就会直接通过AsyncMethodBuilderCore.ThrowAsync抛到全局同步上下文,不会被局部catch捕获。


修复方案

  1. 扩大try块覆盖范围+提前判空
    方法入口先添加Fragment状态校验,把所有业务逻辑都放进try块覆盖范围,删除finally外冗余的UI调用:
    private async Task SearchMostLessViewsAsync(DateTime dateFrom, DateTime dateTo, int amountOfNumbersSelected, int frequencyOption, int fromDrawNumber, int toDrawNumber)
    {
        // 入口先校验状态,避免后续空引用
        if (Activity == null || Activity.IsFinishing || Activity.IsDestroyed) 
            return;
        try
        {
            Microsoft.AppCenter.Analytics.Analytics.TrackEvent($"{typeof(FragmentDrawsNumbersFrequency).Name}.{nameof(SearchMostLessViewsAsync)}",
                new Dictionary<string, string>()
                    {
                        {nameof(dateFrom), dateFrom.ToString()},
                        {nameof(dateTo), dateTo.ToString()},
                        {nameof(amountOfNumbersSelected), amountOfNumbersSelected.ToString()},
                        {nameof(frequencyOption), frequencyOption.ToString()},
                        {nameof(fromDrawNumber), fromDrawNumber.ToString()},
                        {nameof(toDrawNumber), toDrawNumber.ToString()},
                    }
                );
            ((MainActivity)Activity).DisplayLoadingMessage(true, GetString(Resource.String.Common_SearchTitle),
                GetString(Resource.String.Common_SearchMessage));
    
            var task = Task.Run(async () =>
            {
                var textResult = await SearchLeast(dateFrom, dateTo, amountOfNumbersSelected, frequencyOption, fromDrawNumber, toDrawNumber).ConfigureAwait(false);
    
                if (!string.IsNullOrEmpty(textResult))
                {
                    UpdateHistoryList(textResult);
                    DatabaseFunctions.SaveHistoryList(HistoryList, Settings.DrawsNumbersFrequencyHistoryListViewKey);
                    // 切回UI线程执行UI操作,同时校验状态
                    Activity.RunOnUiThread(() => 
                    {
                        if (Activity != null && !Activity.IsFinishing && !Activity.IsDestroyed)
                        {
                            ((MainActivity)Activity).ShowSearchResults(textResult);
                        }
                    });
                }
            }, ApplicationState.GetCancellationToken());
    
            await task.ConfigureAwait(false);
        }
        catch (TaskCanceledException tce)
        {
            Console.WriteLine($"{nameof(TaskCanceledException)} thrown with message: {tce.Message}");
        }
        catch (System.ObjectDisposedException ode)
        {
            Console.WriteLine($"{nameof(System.ObjectDisposedException)} thrown with message: {ode.Message}");
        }
        catch (System.OperationCanceledException e)
        {
            Console.WriteLine($"{nameof(System.OperationCanceledException)} thrown with message: {e.Message}");
        }
        catch (NullReferenceException nre)
        {
            Console.WriteLine($"{nameof(NullReferenceException)} thrown with message: {nre.Message}");
        }
        // 新增全局异常兜底,避免漏网
        catch (Exception ex)
        {
            Console.WriteLine($"Unexpected exception: {ex.Message}");
        }
        finally
        {
            ApplicationState.DisposeCancellationTokenSource();
            if (Activity != null && !Activity.IsFinishing && !Activity.IsDestroyed)
            {
                ((MainActivity)Activity).DisplayLoadingMessage(false);
            }
        }
    }
    
  2. 移除不必要的ConfigureAwait(false)
    如果Task.Run内部后续逻辑需要操作UI,就不要给await SearchLeast加ConfigureAwait(false),让await之后的代码自动切回原UI同步上下文,避免手动切线程的额外开销和风险。
  3. 调用层兜底
    在触发该方法的点击事件回调(async void类型)外层也加一层try/catch,避免极端场景的异常逃逸。

内容的提问来源于stack exchange,提问作者CDrosos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 21:15:04