无法理解为什么我得到NullReferenceException

时间:2016-12-14 03:33:30

标签: c# multithreading nullreferenceexception

我有一段代码正在从队列中读取,处理一个项目(在自己的线程中),然后重复直到队列为空。

public ActionResult GetOrdersAsync() {

        int count = 0;
        SyncDM sync = _common.StartSync();

        while (sync != null && sync.SyncId != 0) {

            int customerId;
            bool result = int.TryParse(sync.Payload, out customerId);
            if (result) {
                Task.Run(() => GetOrders(sync.SyncId, customerId));
            }

            count++;
            //Process the next Sync
            sync = _common.StartSync();

        }

        return Json(new JsonModel {
            Message = "Started " + count + " instances of GetOrders",
            Success = count > 0
        });

    }

StartSync()要么从队列中删除项目,要么在队列为空时返回null。 GetOrders()处理对象。

问题是有时代码会在此行引发NullReferenceException     Task.Run(()=> GetOrders(sync.SyncId,customerId));

在调试器中,Sync为null(异常原因),但customerId具有值。这告诉我同步在前一行有一个值。这让我感到困惑,我认为它与Task.Run和线程有关,但我不明白本地范围的变量如何自发地改变它的值。

1 个答案:

答案 0 :(得分:6)

在您的任务有机会对其进行操作之前,您正在更新sync的引用。请注意,任务不一定立即开始。在某些情况下,您的任务可能会在进一步执行以下操作后开始:

sync = _common.StartSync();

现在,您对sync的引用可能为null,当您的任务进入sync.SyncId时,您将获得空引用异常。

将您的代码更改为以下内容:

if (result) {
    var syncId = sync.SyncId;
    Task.Run(() => GetOrders(syncId, customerId));
}

这是有效的,因为我们只想传递Id。如果你想传递对象本身怎么办?您需要创建一个新的变量,它将在闭包之外 进行修改:

if (result) {
    var capturedSync = sync;
    //Assuming GetOrders now takes a `Sync`
    Task.Run(() => GetOrders(capturedSync, customerId));
}