奇怪VB.NET用For Each居然會被Fortify掃出有Null Dereference問題,但C#的foreach卻是OK的。
到底是為什麼呢?
最近程式又被Fortify掃出Null Dereference的問題,一般是加入判斷是否為null(Nothing),但以下的Code居然被認為是有Null Dereference問題。
'grdWorklist2是asp.net的GridView
For Each r1 As GridViewRow In grdWorklist2.Rows
Next
但是相同的Code,用C#卻不會被掃出來,如下,
foreach (GridViewRow row in grdWorklist2.Rows)
{
}
後來想說加個OfType是否OK呢? 結果就真的就不會有問題,如下,
Dim gridRowsOfType = grdWorklist2.Rows.OfType(Of GridViewRow)()
For Each r2 As GridViewRow In gridRowsOfType
Next
很直覺的認為grdWorklist2.Rows出來的一定是GridViewRow呀! 為何一定要用OfType呢?
於是透過 .NET Reflector 來看一下,編譯後,程式碼到底變成了什麼呢?
For Each r1 As GridViewRow In grdWorklist2.Rows
Next
變成了以下的內容(C#呈現)
IEnumerator enumerator;
try
{
enumerator = this.grdWorklist2.Rows.GetEnumerator();
while (enumerator.MoveNext())
{
GridViewRow current = (GridViewRow) enumerator.Current;
}
}
finally
{
if (enumerator is IDisposable)
{
(enumerator as IDisposable).Dispose();
}
}
謎題解開了,原來那個 For Each r1 As GridViewRow In grdWorklist2.Rows 中,會有一個直接轉型的程式碼,所以Fortify就認定它有 Null Dereference問題 。
請注意:2013/06/28 修改造成 Null Dereference 的地方,是在 (enumerator as IDisposable).Dispose();
原本是認為因為直接轉型所造成的問題,後來再看一下程式,覺得還是請 Fortify 確認一下認定是否正確,結果問題點是出並不是因為直接轉型的地方,而是在
(enumerator as IDisposable).Dispose(); 的地方,它是認為 變數enumerator 有可能為null,所以在判斷之前要先判斷是否為null,如下
if (enumerator is IDisposable)
=>
if (enumerator != null && enumerator is IDisposable)
不過, enumerator 應該確定不會是null才是呀! 真的還蠻奇怪的!
Dim gridRowsOfType = grdWorklist2.Rows.OfType(Of GridViewRow)()
For Each r2 As GridViewRow In gridRowsOfType
Next
變成了以下的Code,沒有轉型,所以OK!
IEnumerable<GridViewRow> enumerable = Enumerable.OfType<GridViewRow>(this.grdWorklist2.Rows);
foreach (GridViewRow row2 in enumerable)
{
}
所以如果VB.NET中有For Each被掃出 Null Dereference的問題 ,可加入OfType去解掉這問題!
另外,使用 For i As Integer = 0 To grdWorklist2.Rows.Count - 1 也是可以的哦! 如下,
For i As Integer = 0 To grdWorklist2.Rows.Count - 1
Next
或是使用C#來寫也OK哦!
foreach (GridViewRow row in grdWorklist2.Rows)
{
}
=>
foreach (GridViewRow row in this.grdWorklist2.Rows)
{
}
參考資訊
請注意:2013/06/28 修改造成 Null Dereference 的地方,是在 (enumerator as IDisposable).Dispose();
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^