пустое объединение переводит примерно в return x, unless it is null, in which case return y
Мне часто нужно return null if x is null, otherwise return x.y
Я могу использовать return x == null ? null : x.y;
Не плохо, но это null
в середине всегда беспокоит меня - это кажется лишним. Я предпочел бы что-то как return x :: x.y;
, где, что следует ::
оценен, только если, что предшествует, это не null
.
Я вижу это как почти напротив пустой коалесценции, отчасти смешанной в с краткой, встроенной пустой проверкой, но я [почти] уверен, что нет такого оператора в C#.
(Я знаю, что могу записать метод для него в C#; я использую return NullOrValue.of(x, () => x.y);
, но если бы у Вас есть что-нибудь лучше, я хотел бы видеть это также.)
В Groovy есть null-safe dereferencing operator (?.)... Я думаю, это то, что вам нужно.
(Он также называется оператор безопасной навигации.)
Например:
homePostcode = person?.homeAddress?.postcode
Это даст null, если person
, person.homeAddress
или person.homeAddress.postcode
равны null.
(Это теперь доступно в C# 6.0, но не в более ранних версиях)
В Delphi есть оператор: (а не.), Который является нулевым.
Они думали добавить?. оператор в C # 4.0, чтобы сделать то же самое, но с блокировкой.
А пока есть IfNotNull () , который царапает, что зудит. Это конечно больше чем ?. или:, но он позволяет вам составить цепочку операций, которая не вызовет у вас исключение NullReferenceException, если один из членов имеет значение NULL.
Если у вас есть специальный вид замыкания булевой логики, вы можете сделать следующее (пример на javascript):
return x && x.y;
Если x
равен null, то не будет оцениваться x.y
.
В Haskell есть fmap
, который в данном случае, я думаю, эквивалентен Data.Maybe.map
. Haskell чисто функциональный, поэтому то, что вы ищете, будет
fmap select_y x
Если x
есть Nothing
, это возвращает Nothing
. Если x
- Just object
, то возвращается Just (select_y object)
. Не так красиво, как точечная нотация, но учитывая, что это функциональный язык, стили отличаются.
Просто захотелось добавить это в качестве ответа.
Я полагаю, что причина, по которой в C# нет такой вещи, заключается в том, что, в отличие от оператора коалесцирования (который действителен только для ссылочных типов), обратная операция может дать либо ссылочный, либо стоимостной тип (т.е. class x
с членом int y
- поэтому, к сожалению, она была бы непригодна во многих ситуациях.
Однако я не говорю, что не хотел бы этого!
Потенциальным решением этой проблемы было бы автоматическое приведение оператором выражения типа значения в правой части к nullable. Но тогда возникает проблема, что x.y
, где y - int, фактически вернет int?
, что было бы неприятно.
Другим, возможно, лучшим решением было бы возвращение оператором значения по умолчанию (т.е. null или ноль) для типа в правой части, если выражение в левой части равно null. Но тогда возникают проблемы с различением сценариев, в которых ноль/нуль действительно был прочитан из x.y
или же он был предоставлен оператором безопасного доступа.
Мы рассматривали возможность добавления?. в C # 4. Это не помогло; это функция «приятно иметь», а не «обязательно». Мы еще раз рассмотрим это для гипотетических будущих версий языка, но на вашем месте я бы не стал задерживать дыхание. С течением времени это вряд ли станет более важным. : -)
В Haskell можно использовать оператор >>
:
Nothing >> Nothing
is Nothing
Nothing >> Just 1
is Nothing
Just 2 >> Nothing
is Nothing
Just 2 >> Just 1
is Just 1
PowerShell позволяет ссылаться на свойства (но не вызывать методы) по пустой ссылке, и она вернет null, если экземпляр имеет значение NULL. Сделать это можно на любой глубине. Я надеялся, что динамическая функция C # 4 будет поддерживать это, но это не так.
$x = $null
$result = $x.y # $result is null
$x = New-Object PSObject
$x | Add-Member NoteProperty y 'test'
$result = $x.y # $result is 'test'
Это некрасиво, но вы можете добавить метод расширения, который будет работать так, как вы описываете.
public static TResult SafeGet<T, TResult>(this T obj, Func<T, TResult> selector) {
if (obj == null) { return default(TResult); }
else { return selector(obj); }
}
var myClass = new MyClass();
var result = myClass.SafeGet(x=>x.SomeProp);