2012-02-24 75 views
17

如果我有類似下面的代碼:可能使用?? (合併運算符)與DBNull?

while(myDataReader.Read()) 
{ 
    myObject.intVal = Convert.ToInt32(myDataReader["mycolumn"] ?? 0); 
} 

它引發錯誤:

Object cannot be cast from DBNull to other types.

定義intVal爲可空int是不是一種選擇。有沒有辦法讓我做到這一點?

+3

可能重複(HTTP://計算器.com/questions/2433155/handle-dbnull-in-c-sharp) – BoltClock 2012-02-24 19:32:47

回答

13

你可以使用擴展方法? (註銷我的頭頂部)

public static class DataReaderExtensions 
{ 
    public static T Read<T>(this SqlDataReader reader, string column, T defaultValue = default(T)) 
    { 
     var value = reader[column]; 

     return (T)((DBNull.Value.Equals(value)) 
        ? defaultValue 
        : Convert.ChangeType(value, typeof(T))); 
    } 
} 

你會使用它像:

while(myDataReader.Read()) 
{ 
    int i = myDataReader.Read<int>("mycolumn", 0); 
} 
+0

我最終選擇了擴展方法路線。我遇到了'Convert.ChangeType ...'部分的錯誤,所以我做了一些小改動。 – 2012-02-24 20:24:50

+0

你可以用你必須做的'小改動'來更新我的答案嗎? – 2012-02-24 20:30:03

+0

其實我仍然有一些麻煩讓演員工作。 '轉換。ChangeType(reader [column],typeof(T))'不能編譯,所以我切換到這個引發運行時異常的'(T)reader [column]'。有任何想法嗎? – 2012-02-24 20:35:35

2

爲什麼不使用非空合併運算符以外的東西(DBNull.Value = null!):

​​

你總是可以包起來,有着簡潔的擴展方法:

public static T Read<T>(this DataReader reader, string column, T defaultVal) 
{ 
    if(reader[column] == DBNull.Value) return defaultVal; 
    return Convert.ChangeType(reader[column], typeof(T)); 
} 
+1

如果我能把它拉開,我認爲它是一個三元的,但如果'''看起來更乾淨。 – 2012-02-24 19:35:46

+0

@AbeMiessler我不認爲''''將與'DBNull'一起使用;它實際上不是'null'。 – dlev 2012-02-24 19:36:24

+0

你反過來了。另外我會建議這種方法不是那麼高效。 – nawfal 2012-02-24 19:38:49

1

不,僅適用於空值。

對象的擴展方法檢查DBNull,並返回一個默認值呢?

//may not compile or be syntactically correct! Just the general idea. 
public static object DefaultIfDBNull(this object TheObject, object DefaultValue) 
{ 
    if(TheObject is DBNull) 
     return DefaultValue; 
    return TheObject; 
} 
+0

爲什麼不使用泛型而不是'object'? – dlev 2012-02-24 19:35:43

+0

@dlev在處理非通用數據讀取器的情況下,我認爲這會更容易。這只是我的頭頂。來自insta的通用答案看起來相當不錯。 – asawyer 2012-02-24 19:37:34

5

如何像:

object x = DBNull.Value; 
int y = (x as Int32?).GetValueOrDefault(); //This will be 0 

或者你的情況:

int i = (myDataReader["mycolumn"] as Int32?).GetValueOrDefault(); 
+0

正如John Saunders在他對「可能重複」問題的回答中指出的那樣,這種方法的缺點是如果列的數據類型發生變化,則無法引發異常。例如,如果「mycolumn」擁有42的「short」值,則變量「i」將具有值「0」。直接強制轉換會引發異常,提請注意代碼和數據庫之間的類型不匹配。 – phoog 2012-02-24 19:56:53

+0

@phoog - 有效的點,我想每種方法都有其優點和缺點。就我個人而言,我喜歡我的數據庫和代碼儘可能緊密結合。我要麼在代碼中使用'int?',要麼在數據庫中不允許'null'。 – 2012-02-24 20:07:49

6

你能簡單地使用Int32.Tryparse

int number; 
bool result = Int32.TryParse(myDataReader["mycolumn"].ToString(), out number); 

按照MSDNnumber將包含0,如果轉換失敗

+1

+1,很好的答案。這可能會奏效,但我實際上正試圖分配的int是一個對象屬性,它不適用於'out'。 – 2012-02-24 19:51:10

+5

這不會編譯,是嗎?數據閱讀器索引器返回一個對象引用,TryParse接受一個字符串參數。當然,您可以在對象上調用ToString,但構造int的字符串表示的效率相當低,因此您可以解析它。拆箱轉換會更有效率。 – phoog 2012-02-24 19:53:14

+0

@phoog,好點。如果它是空的ToString反正會彈。可以使用'as string'代替。 – 2012-02-24 19:55:47

10

這裏有一個選擇:在C#中處理的DBNull]的

while (myDataReader.Read()) 
{ 
    myObject.intVal = (myDataReader["mycolumn"] as int? ?? 0); 
} 
+0

絕對是最好的方式!謝謝Edyn。 – ClownCoder 2016-03-31 03:51:19

+0

明智的答案!很乾淨。 – 2016-08-10 16:43:51