最近研究了一下C#2.0中的可空類型探索一些有趣的事實,請看代碼
int? a = null;
object b = a;
則下面的邏輯運算式結果如何?a==null //true
b==null //false
奇怪嗎?
第一個邏輯運算式為true是意料之中的,而第二個運算式為false就有些意料之外了,但仔細想一下,就會感覺有它存在的道理。我們都知道int?就是Nullable<int>的縮寫,而在.Net Framework中Nullable<T>實現其實是一個繼承自實值型別的結構,只是這個結構多了個屬性HasValue,用來標識結構中是否有值,這樣再理解上面的結果就不奇怪了,因為語句object b = a;會有一個裝箱操作,也就是b中的引址為指向裝箱後的a結構,而不是Null 參考,因此就會有上面的結果了。
這點只是C#語言中的一些小細節,但在很多時候可能會引起些不可以預料的事果,比如微軟發布的DataAccessBlock中用來把預存程序的參數數組的時候SqlHelper中的代碼 private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if ((p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input) &&
(p.Value == null))
{
p.Value = DBNull.Value;
}
command.Parameters.Add(p);
}
}
}
}
在某些情況下將不在有效,因為p.Value為空白的判斷p.Value==null在p.Value中存貯可空類型的時候可能會失效(如果p.Value中存貯的對象是可空類型,而它的值剛好為空白時p.Value == null會返回false但在這種情況下我們仍應該將p.Value賦值為DBNull.Value),這時會導致運行對象沒有實現IConvertable的出錯資訊。 改後代碼如下: private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
if (command == null) throw new ArgumentNullException("command");
if (commandParameters != null)
{
foreach (SqlParameter p in commandParameters)
{
if (p != null)
{
if (p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input)
{
if (p.Value != null)
{
Type typeInf = p.Value.GetType();
if (typeInf.Name == "Nullable`1" &&
(bool)typeInf.GetProperty("HasValue").GetValue(p.Value, null) == false)
{
p.Value = DBNull.Value;
}
}
else
{
p.Value = DBNull.Value;
}
}
command.Parameters.Add(p);
}
}
}
}
總的來講可空類型為我們提供了很大的方便,特別是在對資料庫的可空欄位的操作提供了方便,但使用時應注意上面的情況才能作到萬無一失。