Нулевой оператор в c # позволяет сократить код
if (_mywidget == null)
return new Widget();
else
return _mywidget;
Вниз до:
return _mywidget ?? new Widget();
Я продолжаю находить, что полезным оператором, который я хотел бы иметь в C #, был бы тот, который позволял бы вам возвращать свойство объекта или какое-либо другое значение, если объект нулевой. Поэтому я хотел бы заменить
if (_mywidget == null)
return 5;
else
return _mywidget.Length;
С:
return _mywidget.Length ??! 5;
Я не могу не думать, что должна быть какая-то причина, по которой этот оператор не существует. Это запах кода? Есть ли лучший способ написать это? (Я знаю о шаблоне нулевого объекта, но, кажется, излишне использовать его для замены этих четырех строк кода.)
c#
code-smell
null
Бен Фултон
источник
источник
??!
является оператором в C ++. :-)Ответы:
Я очень хочу функцию языка C #, которая позволяет мне безопасно выполнять x.Prop.SomeOtherProp.ThirdProp, не проверяя каждый из них на ноль. В одной кодовой базе, где мне приходилось много выполнять такие «глубокие обходы свойств», я написал метод расширения под названием Navigate, который проглотил исключения NullReferenceExceptions и вместо этого возвратил значение по умолчанию. Так что я мог бы сделать что-то вроде этого:
Недостатком этого является то, что он имеет другой запах кода: проглоченные исключения. Если вы хотите сделать что-то вроде этого «правильно», вы можете взять lamdba в качестве выражения и изменить выражение на лету, чтобы добавить нулевые проверки вокруг каждого метода доступа к свойству. Я пошел на «быстрый и грязный» и не реализовал это «лучше». Но, возможно, когда у меня появятся запасные мыслительные циклы, я еще раз вернусь к этому и выложу куда-нибудь.
Чтобы более прямо ответить на ваш вопрос, я предполагаю, что причина, по которой это не функция, заключается в том, что стоимость реализации функции превышает выгоду от наличия функции. Команда C # должна выбирать, на какие функции ориентироваться, а эта еще не достигла вершины. Просто предположение, хотя у меня нет никакой инсайдерской информации.
источник
Я верю, что вы сможете сделать это с C # 6 довольно просто:
Обратите внимание на нулевой условный оператор
?.
слева._mywidget?.Length
возвращает ноль, если_mywidget
ноль.Простой троичный оператор может быть проще для чтения, как и предполагали другие.
источник
Это действительно только предположение, почему они этого не сделали. В конце концов, я не верю ?? был в первой версии C #.
В любом случае, я бы просто использовал условный оператор и назвал бы его через день:
?? это просто ярлык для условного оператора.
источник
5
ответ, если его там нет. Вы должны посмотреть на свой дизайн, прежде чем начать спрашивать специальных операторов.Это выглядит как троичный оператор:
источник
Лично я думаю, что это до читабельности. В первом примере
??
перевод довольно красиво звучит как «Ты здесь? Нет, давай сделаем это».Во втором примере
??!
явно WTF и ничего не значит для программиста .... объект не существует, поэтому я не могу получить это свойство, поэтому я верну 5. Что это вообще значит? Что такое 5? Как мы приходим к выводу, что 5 является хорошим значением?Короче говоря, первый пример имеет смысл ... не там, это новое . Во вторых, это открыто для обсуждения.
источник
(foo() != ERROR)??!??! cerr << "Error occurred" << endl;
)5
. Я действительно думаю, что есть еще одна проблема, которая заключается в том, что вы должны сделать что-то вроде этого, тогда как в вашем первом примере необходимость совершенно очевидна, особенно в таких вещах, как менеджеры кэша.Я думаю, что люди слишком увязли в «5», которые вы возвращаете ... возможно, 0 было бы лучше :)
Во всяком случае, я думаю, что проблема в том, что на
??!
самом деле это не отдельный оператор. Подумайте, что бы это значило:В этом случае это не имеет смысла: это имеет смысл, только если левый операнд является средством доступа к свойству. Или как насчет этого:
Там есть средство доступа к свойствам, но я все еще не думаю, что это имеет смысл (если
myWidget
естьnull
, значит ли это , что мы вообще не вызываемFoo()
?), Или это просто ошибка?Я думаю, что проблема в том, что он не вписывается в язык так
??
же естественно, как в тексте.источник
Кто-то создал служебный класс, который сделает это за вас. Но я не могу найти это. То, что я нашел, было что-то похожее на форумах MSDN (посмотрите на второй ответ).
Немного поработав, вы можете расширить его для оценки вызовов методов и других выражений, которые не поддерживаются в этом примере. Вы также можете расширить его, чтобы принять значение по умолчанию.
источник
Я понимаю, откуда ты. Кажется, что все обвиваются вокруг акселя с примером, который вы предоставили. Хотя я согласен с тем, что магические числа - плохая идея, для некоторых свойств будет использоваться эквивалент оператора нулевого объединения.
Например, у вас есть объекты, связанные с картой, и вы хотите, чтобы они были на нужной высоте. Карты DTED могут иметь дыры в своих данных, поэтому можно иметь нулевое значение, а также значения в диапазоне от -100 до ~ 8900 метров. Вы можете захотеть что-то вроде:
В этом случае нулевой оператор связывания заполняет высоту по умолчанию, если координаты еще не установлены, или объект координат не может загрузить данные DTED для этого местоположения.
Я считаю это очень ценным, но мои предположения о том, почему это не было сделано, ограничены сложностью компилятора. Могут быть случаи, когда поведение не будет таким предсказуемым.
источник
Когда я не имел дело с глубоко вложенными, я использовал это (до того, как в C # 6 появился нулевой оператор объединения). Для меня это довольно ясно, но, может быть, это потому, что я привык к этому, другие люди могут найти это запутанным.
Конечно, это не всегда применимо, поскольку иногда свойство, к которому вам нужно получить доступ, не может быть установлено напрямую, или когда строительство самого объекта является дорогостоящим, среди других причин.
Другой альтернативой является использование шаблона NullObject . Вы определяете один статический экземпляр класса с разумными значениями по умолчанию и используете его вместо этого.
источник
Магические числа обычно имеют неприятный запах. Если 5 - произвольное число, то лучше разобрать его так, чтобы оно было более четко задокументировано. Исключением, на мой взгляд, будет, если у вас есть набор значений, которые действуют как значения по умолчанию в определенном контексте.
Если у вас есть набор значений по умолчанию для объекта, вы можете создать его подкласс для создания одноэлементного экземпляра по умолчанию.
Что-то вроде: return (myobj ?? default_obj) .Length
источник
Свойство length обычно является типом значения, поэтому оно не может быть нулевым, поэтому оператор объединения с нулем здесь не имеет смысла.
Но вы можете сделать это с помощью свойства, которое является ссылочным типом, например:
var window = App.Current.MainWindow ?? new Window();
источник
Я видел кого-то с подобной идеей и раньше, но большую часть времени вы хотели бы также назначить новое значение в нулевое поле, что-то вроде:
поэтому идея заключалась в том, чтобы объединить
??
и=
присваивание в:Я думаю, что это имеет больше смысла, чем использование восклицательного знака.
Эта идея не моя, но мне очень нравится :)
источник
return _obj ?? new Class();
здесь нет необходимости??=
.