Существует ли "противоположность" нулевому коалесцирующему оператору? (... на любом языке?)
null коалесценция грубо приближается к 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
.
Я рассматриваю это как почти противоположное нулевой коалесценции, смешанное с кратким встроенным нулевым проверкой, но я [почти] уверен, что в С# такого оператора нет.
Существуют ли другие языки, имеющие такой оператор? Если да, то что называется?
(Я знаю, что могу написать метод для него в С#, я использую return NullOrValue.of(x, () => x.y);
, но если у вас есть что-то лучше, я тоже хотел бы это увидеть.)
Ответы
Ответ 1
Там нулевой оператор разыменования (?.) в Groovy... Я думаю, что вы после.
(Он также называется безопасным навигационным оператором .)
Например:
homePostcode = person?.homeAddress?.postcode
Это даст значение null, если person
, person.homeAddress
или person.homeAddress.postcode
равно null.
(Теперь это доступно в С# 6.0, но не в более ранних версиях)
Ответ 2
Мы рассмотрели добавление?. к С# 4. Он не сделал разреза; это "хорошо иметь" функцию, а не функцию "нужно иметь". Мы рассмотрим это снова для гипотетических будущих версий языка, но я бы не задерживал дыхание, ожидая, если бы я был вами. С течением времени он вряд ли станет более важным.: -)
Ответ 3
Если у вас есть специальная логическая логика короткого замыкания, вы можете сделать это (пример javascript):
return x && x.y;
Если x
равно null, то он не будет оценивать x.y
.
Ответ 4
Мне просто хотелось добавить это как ответ.
Я предполагаю, что в С# нет такой вещи, потому что, в отличие от оператора коалесценции (который действителен только для ссылочных типов), обратная операция может приводить либо к эталонному, либо к типу значений (т.е. class x
с членом int y
- поэтому он, к сожалению, будет непригодным для использования во многих ситуациях.
Я не говорю, однако, что я не хотел бы видеть это!
Потенциальное решение этой проблемы позволит оператору автоматически поднять выражение типа значения в правой части до нулевой. Но тогда у вас есть проблема, что x.y
, где y является int, действительно вернет int?
, который будет больно.
Другим, вероятно, лучшим решением было бы для оператора вернуть значение по умолчанию (т.е. нуль или ноль) для типа в правой части, если выражение слева имеет значение null. Но тогда у вас есть проблемы с различием сценариев, где нуль/нуль фактически был прочитан из x.y
или был ли он предоставлен оператором безопасного доступа.
Ответ 5
Delphi имеет оператор: (а не.), который является нулевым.
Они думали о добавлении?. оператор на С# 4.0, чтобы сделать то же самое, но получил блок прерывания.
Тем временем, IfNotNull(), который выглядит как царапины, которые зудят. Это, конечно, больше, чем?. или:, но это позволяет вам составить цепочку операций, которая не будет вызывать исключение NullReferenceException у вас, если один из членов имеет значение null.
Ответ 6
В Haskell вы можете использовать оператор >>
:
-
Nothing >> Nothing
Nothing
-
Nothing >> Just 1
Nothing
-
Just 2 >> Nothing
Nothing
-
Just 2 >> Just 1
Just 1
Ответ 7
Haskell имеет fmap
, что в этом случае я считаю эквивалентным Data.Maybe.map
. Haskell является чисто функциональным, поэтому то, что вы ищете, будет
fmap select_y x
Если x
- Nothing
, это возвращает Nothing
. Если x
равно Just object
, это возвращает Just (select_y object)
. Не так красиво, как точечная нотация, но учитывая, что это функциональный язык, стили разные.
Ответ 8
PowerShell позволяет ссылаться на свойства (но не на методы вызова) на нулевую ссылку и возвращает значение null, если экземпляр имеет значение null. Вы можете сделать это на любой глубине. Я надеялся, что динамическая функция С# 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);
Ответ 9
Создайте статический экземпляр вашего класса где-нибудь со всеми правильными значениями по умолчанию для членов.
Например:
z = new Thingy { y=null };
а затем вместо
return x != null ? x.y : null;
вы можете написать
return (x ?? z).y;
Ответ 10
public class ok<T> {
T s;
public static implicit operator ok<T>(T s) { return new ok<T> { s = s }; }
public static implicit operator T(ok<T> _) { return _.s; }
public static bool operator true(ok<T> _) { return _.s != null; }
public static bool operator false(ok<T> _) { return _.s == null; }
public static ok<T> operator &(ok<T> x, ok<T> y) { return y; }
}
Мне часто нужна эта логика для строк:
using ok = ok<string>;
...
string bob = null;
string joe = "joe";
string name = (ok)bob && bob.ToUpper(); // name == null, no error thrown
string boss = (ok)joe && joe.ToUpper(); // boss == "JOE"
Ответ 11
Это добавляется в С# vNext (Roslyn powered С#, выпуски с Visual Studio 2014).
Он называется нулевым распространением и указан здесь как полный.
https://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status
Он также указан здесь как полный:
https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c