可為 Null 的運算子 (F#)
可為 null 的運算子是使用可為 null 的算術型別,在一或兩個邊的二進位算術或比較運算子。經常當您使用的資料來源,例如允許 null 值,來代替實際值的資料庫時,才可為 null 的型別就會發生。可為 null 的運算子通常用於查詢運算式。除了可為 null 的算術和比較運算子,轉換運算子可用於可為 null 的型別之間轉換。也有特定的查詢運算子可為 null 的版本。
可為 Null 的運算子的表格
下表列出可為 null F# 語言中支援的運算子。
在左邊的 [可為 null |
在右邊的 [可為 null |
可為 null 的兩面 |
備註
可為 null 的運算子會包含在 NullableOperators 命名空間中的模組 Microsoft.FSharp.Linq。可為 null 的資料型別是Nullable<T>。
在查詢運算式中,選取允許設定 null 值,而不是值的資料來源的資料時,會發生可為 null 的型別。在 SQL Server 資料庫中,每個資料表中的資料行具有屬性,指出是否允許 null。如果允許 null 值,從資料庫傳回的資料可以包含 null 值無法表示的基本資料型別類似int, float,依此類推。因此,將資料傳回成System.Nullable<int>而不是int,和System.Nullable<float>而不是float。實際的值可以取自Nullable<T>物件藉由使用Value屬性,而您可以判斷Nullable<T>物件的值,藉由呼叫HasValue方法。另一個有用的方法是GetValueOrDefault方法,可讓您取得的值或預設值為適當的型別。預設值是某種形式的 「 零 」 的值,如 0、 0.0 或false。
可為 null 的型別可能會轉換成不可為 null 的基本型別,使用一般的轉換運算子,如int或float。它也可將一種可為 null 的型別轉換為另一個 null 的型別藉由可為 null 的型別轉換運算子。適當的轉換運算子具有相同的名稱,做為標準的但它們是獨立的模組中,在 Nullable 中的模組 Microsoft.FSharp.Linq 命名空間。一般而言,使用查詢運算式時開啟這個命名空間。在此情況下,您可以使用可為 null 的轉換運算子,加上前置詞Nullable.到適當的轉換運算子,如下列程式碼所示。
open Microsoft.Fsharp.Linq
let nullableInt = new System.Nullable<int>(10)
// Use the Nullable.float conversion operator to convert from one nullable type to another nullable type.
let nullableFloat = Nullable.float nullableInt
// Use the regular non-nullable float operator to convert to a non-nullable float.
printfn "%f" (float nullableFloat)
輸出為 10.000000。
查詢運算子的可為 null 的資料欄位,例如sumByNullable,也存在的查詢運算式中使用。查詢運算子為不可為 null 的型別並不具有可為 null 的型別,型別相容,所以當您使用可為 null 的資料值時,您必須使用適當的查詢運算式的可為 null 的版本。如需詳細資訊,請參閱 查詢運算式 (F#)。
下列範例會顯示在 F# 查詢運算式中用可為 null 的運算子。第一個查詢會顯示您,如何撰寫這個查詢沒有可為 null 的運算子。 第二個查詢會顯示可為 null 的運算子會使用對等查詢。完整的內容,包括如何將資料庫設定為使用這個範例程式碼中,請參閱逐步解說:使用型別提供者存取 SQL 資料庫 (F#)。
open System
open System.Data
open System.Data.Linq
open Microsoft.FSharp.Data.TypeProviders
open Microsoft.FSharp.Linq
[<Generate>]
type dbSchema = SqlDataConnection<"Data Source=MYSERVER\INSTANCE;Initial Catalog=MyDatabase;Integrated Security=SSPI;">
let db = dbSchema.GetDataContext()
query {
for row in db.Table2 do
where (row.TestData1.HasValue && row.TestData1.Value > 2)
select row
}
|> Seq.iter (fun row -> printfn "%d %s" row.TestData1.Value row.Name)
query {
for row in db.Table2 do
// Use a nullable operator ?>
where (row.TestData1 ?> 2)
select row
}
|> Seq.iter (fun row -> printfn "%d %s" (row.TestData1.GetValueOrDefault()) row.Name)