對於下面的一段代碼(.NET v4.0.30319),我得到了下面第二個繼續中指出的空引用異常。空引用 - 任務ContinueWith()
最有趣的是,這個問題只發生在8GB內存的機器上,但其他用戶擁有16GB或更多,他們沒有報告任何問題,這是一個非常間歇性的問題,導致我懷疑垃圾收集問題。
GetData()
可以被多次調用,所以_businessObjectTask的第一個繼續只會被調用一次,因爲_businessObjects將從該點向前填充。
我想象被拋出的異常Object reference not set to an instance of an object
,因爲無論
_businessObjectTask
爲null,並且它不能從空任務繼續。被傳遞作爲參數items
變量爲空以某種方式
在我的日誌文件中的行號(748)指向所述一個下面和未突出顯示lambda表達式指向#1的上方,而不是#2。我已經在Visual Studio中玩過了,每個businessObjectTask.ContinueWith()
之後的行被認爲是不同的,即如果它是lambda表達式中的空引用,它會給出不同的行號748
任何幫助將不勝感激。
編輯: 這與What is a NullReferenceException, and how do I fix it?無關,因爲這是對空引用的更基本的解釋,而這更復雜和更微妙。
異常
堆棧跟蹤(編輯與啞類和命名空間的名稱簡單)
Object reference not set to an instance of an object.
at ApplicationNamespace.ClassName`1.<>c__DisplayClass4e.<GetData>b__44(Task`1 t) in e:\ClassName.cs:line 748
at System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
代碼的全部細節
private static IDictionary<string, IBusinessObject> _businessObjects;
private Task<IDictionary<string, IBusinessObject>> _businessObjectTask;
public Task GetData(IList<TBusinessItem> items))
{
Log.Info("Starting GetData()");
if (_businessObjects == null)
{
var businessObjectService = ServiceLocator.Current.GetInstance<IBusinessObjectService>();
_businessObjectTask = businessObjectService.GetData(CancellationToken.None)
.ContinueWith
(
t =>
{
_businessObjects = t.Result.ToDictionary(e => e.ItemId);
return _businessObjects;
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Current
);
}
var taskSetLEData = _businessObjectTask.ContinueWith // Line 748 in my code - "Object reference not set to an instance of an object." thrown here
(
task =>
{
items.ToList().ForEach
(
item =>
{
IBusinessObject businessObject;
_businessObjects.TryGetValue(item.Id, out businessObject);
item.BusinessObject = businessObject;
}
);
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default
);
}
分辨率:
因此,在使用了我從這個問題中學到的東西之後,我回到了原始代碼,並將其全部弄清楚了。
原來這個NRE的原因是因爲_businessObjectTask
是非靜態的,因爲_businessObjects
是靜態的。
這意味着_businessObjects
爲空,第一次GetData()
被調用,然後將_businessObjectTask
設置爲非空值。然後當_businessObjectTask.ContinueWith
被調用時它是非空的,並繼續沒有問題。
但是,如果上面這個類的第二個實例被實例化,_businessObjects
已經被填充,所以_businessObjectTask
保持爲空。然後當_businessObjectTask.ContinueWith
被調用時,引發_businessObjectTask
的NRE。
有幾個選項我可以採取,但我最終刪除_businessObjectTask
同步方法調用,這意味着我不需要使用延續了,我設置_businessObjects
一次。
GetData是否被多個線程並行調用? –
@Ciaran Martin,您是否確定*您已完整發布代碼?你很清楚有一場比賽,但是在檢查'_businessObjectTask' for null和設置它之間,以及對'ContinueWith',*或*任何代碼設置_businessObjectTask的調用之間,我沒有看到任何'await'返回null –
@ KirillShlenskiy我沒有粘貼整個代碼,但所有相關的部分都在那裏。我更新了問題和標籤,聲明我使用.NET 4.0,這意味着異步和等待不可用 –