这是如何生成空引用异常的?

时间:2016-06-08 07:29:43

标签: c# windows-runtime

以下代码引发System.NullReferenceException:

        if (!App.AppIsSuspending && groupedItemsViewSource != null)
            groupedItemsViewSource.Source = null;

特别是在Windows.UI.Xaml.Data.CollectionViewSource.put_Source(Object value)中。

我真的很难理解如何或为何会发生这种情况。我对此有何误解?

我想我可以把它包起来试试......但是我真的不明白为什么会爆炸。

这是在Windows Phone上运行的WinRT应用程序,但我没有足够的遥测信息告诉我手机是否运行Windows Phone 8.1或Windows 10 Mobile。

更新:为了更清楚,异常实际上发生在CollectionViewSource.put_source中。我怀疑底层代码中有一个错误是试图释放以前的值,但是没有测试它可能为null。这是实际的异常记录:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Windows.UI.Xaml.Data.CollectionViewSource.put_Source(Object value)
   at Relative_History.ViewEvent.<OnNavigatedFrom>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__3(Object state)
   at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()

我要写一个小型的演示应用来测试我的理论。我打算删除这个问题,因为我可以做更多的研究,但人们已经开始回答了,所以觉得做错了。

更新:在XAML中为引发异常的页面声明了segmentationItemsViewSource,因此:

<Page.Resources>
    <CollectionViewSource
        x:Name="groupedItemsViewSource"
        ItemsPath="GroupMembers"
        IsSourceGrouped="True"/>
</Page.Resources>

然而,编写一个简单的单页应用程序:

groupedItemsViewSource.Source = null;
代码隐藏中的

不会触发相同的行为。我已经使用WP8.1和W10M仿真器对此进行了测试。

我有点不确定为什么异步位也包含在异常日志中。完整的OnNavigatedFrom是:

    protected override async void OnNavigatedFrom(NavigationEventArgs e)
    {
        Debug.WriteLine("ViewEvent:OnNavigatedFrom");

        if (!App.AppIsSuspending && groupedItemsViewSource != null)
            groupedItemsViewSource.Source = null;

        if (evm != null)
        {
            evm.GroupBuildingCompleted -= HandleGroupBuildingCompleted;
            await evm.CancelGroupBuilding();

            if (!App.AppIsSuspending)
            {
                evm.NoLongerInUse();
                evm = null;
            }
        }

        navigationHelper.OnNavigatedFrom(e);

        if (!App.AppIsSuspending)
        {
            this.navigationHelper.LoadState -= navigationHelper_LoadState;
            this.navigationHelper.SaveState -= navigationHelper_SaveState;
#if WINDOWS_APP
            this.SizeChanged -= ViewEvent_SizeChanged;
#endif
        }
    }

并且,正如您所看到的,没有任何异步代码导致 groupedItemsViewSource.Source = null 行。

更新:我还在试图弄清楚异步是如何在异常堆栈中扮演一个角色的。除非我误解了事情,否则在Relative_History.ViewEvent.d__12.MoveNext()会建议代码在等待之后返回?但OnNavigatedFrom中唯一的等待是在我将groupsItemsViewSource.Source设置为null之后...

或者我是否误解了异常堆栈跟踪?

1 个答案:

答案 0 :(得分:0)

你在其他地方(在不同的线程中)将groupsItemsViewSource设置为null吗?

主题1:

if (!App.AppIsSuspending && groupedItemsViewSource != null)
    groupedItemsViewSource.Source = null;

主题2:

groupedItemsViewSource = null;

如果是这样的话: 可能会发生您的线程1的代码进行检查,然后线程2将变量设置为null,然后线程1尝试使用看到的结果访问源。

为防止这种情况,您可以使用.Net的锁定机制。

在班级中定义一个锁定字段

e.g:

object lockGroupedItemsViewSource = new object();

并在您访问groupedItemsViewSource的所有线程中使用它。

主题1:

lock(lockGroupedItemsViewSource)
{
    if (!App.AppIsSuspending && groupedItemsViewSource != null)
        groupedItemsViewSource.Source = null;
}

主题2:

lock(lockGroupedItemsViewSource)
{
    groupedItemsViewSource=null;
}

干杯

托马斯