[.NET]VB.NET For Each的Null Dereference問題

奇怪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)
{
}

 

參考資訊

HP Enterprise Security

 

請注意:2013/06/28 修改造成 Null Dereference 的地方,是在 (enumerator as IDisposable).Dispose();

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^