По какой-то причине (я еще не выяснил почему) not (obj.ReferenceEquals(value, null))
работает намного лучше, чем value <> null
. Я пишу много кода F #, который используется из C #, поэтому я держу модуль «взаимодействия» , чтобы облегчить работу с null
. Кроме того, если вы предпочитаете сначала «нормальный» случай при сопоставлении с образцом, вы можете использовать активный шаблон:
let (|NotNull|_|) value =
if obj.ReferenceEquals(value, null) then None
else Some()
match value with
| NotNull ->
//do something with value
| _ -> nullArg "value"
Если вам нужно простое выражение if
, это тоже работает:
let inline notNull value = not (obj.ReferenceEquals(value, null))
if notNull value then
//do something with value
UPDATE
Вот некоторые тесты и дополнительная информация о несоответствии производительности:
let inline isNull value = (value = null)
let inline isNullFast value = obj.ReferenceEquals(value, null)
let items = List.init 10000000 (fun _ -> null:obj)
let test f = items |> Seq.forall f |> printfn "%b"
#time "on"
test isNull //Real: 00:00:01.512, CPU: 00:00:01.513, GC gen0: 0, gen1: 0, gen2: 0
test isNullFast //Real: 00:00:00.195, CPU: 00:00:00.202, GC gen0: 0, gen1: 0, gen2: 0
Ускорение на 775% - неплохо. После просмотра кода в .NET Reflector: ReferenceEquals
является нативной / неуправляемой функцией. Оператор =
вызывает HashCompare.GenericEqualityIntrinsic<'T>
, в конечном итоге заканчивая внутренней функцией GenericEqualityObj
. В Reflector эта красота декомпилируется до 122 строк C #. Очевидно, что равенство является сложной проблемой. Для проверки null
достаточно простого сравнения ссылок, поэтому вы можете избежать затрат на семантику более тонкого равенства.
ОБНОВЛЕНИЕ 2
Сопоставление с образцом также позволяет избежать накладных расходов на оператор равенства. Следующая функция работает аналогично ReferenceEquals
, но работает только с типами, определенными вне F # или украшенными [<AllowNullLiteral>]
.
let inline isNullMatch value = match value with null -> true | _ -> false
test isNullMatch //Real: 00:00:00.205, CPU: 00:00:00.202, GC gen0: 0, gen1: 0, gen2: 0
ОБНОВЛЕНИЕ 3
Как отмечается в комментарии Маслоу, в F # 4.0 добавлен оператор isNull
. Он определен так же, как isNullMatch
выше, и, следовательно, работает оптимально.