Как далеко должны 'var' и оператор объединения нулей '??' развлекаться без ущерба для читабельности?

23

Я знаю, что название вопроса очень субъективно, но я столкнулся с использованием ??оператора моими коллегами, где в то же время я был не очень доволен / не чувствовал себя комфортно при применении varв новом готовящемся коде.

Аргумент, приведенный для использования ??оператора был, он убирает читабельность в коде.

Мой вопрос: разве не происходит то же самое, когда вы начинаете использовать var?

Ньюман
источник
49
Если «разработчик» не может понять ??оператор null coalesce после его объяснения, он не должен быть допущен к рабочему коду.
CaffGeek
12
Предлагаю сменить оператора с ?? IfNullThen. ? может быть IfSoChoose, это ElseChoose. + это Добавить. - это вычитание, если оно не одинарное, то отрицательное. - делится между DecrementBeforeUsing и DecrementAfterUsing. В C ++ вы можете сделать это с помощью макросов.
Ли Лувьер
7
@Xaade: это ирония, не так ли? ... правильно? ... Боже, пусть будет ирония (а я атеист).
Стивен Джеурис
10
@ StevenJeuris Это может быть сарказм , но это не ирония .
Кирк Бродхерст
1
@KirkBroadhurst: Я исправлен , всегда путал этих двоих.
Стивен Джеурис

Ответы:

53

Нулевой оператор объединения (??)

Лично я не вижу никаких минусов в использовании этого оператора. Рассмотрим следующие три примера кода, от «простых» до «сложных» новых операторов.

Без магии:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Тернарный оператор:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Нулевое слияние:

string name = null;
Console.WriteLine( name ?? "No name set." );

Причина, по которой эти операторы были изобретены, заключается в том, что они представляют собой очень распространенные операции программирования . Нежелание их использовать, потому что вы к ним не привыкли, просто упрямство . Языки развиваются, функции развиваются, учитесь ими пользоваться!

ключевое слово var

У меня несколько иное мнение о ключевом слове var. Тип переменной часто дает дополнительную информацию о вашем коде. Я считаю, что сокрытие типа с помощью ключевого слова var иногда делает код менее читабельным. Вы меньше знаете, чего ожидать, не используя автоматическое завершение или наводя курсор на идентификаторы, чтобы увидеть, что они на самом деле. На мой взгляд, это приводит к коду, который медленнее для чтения / записи.

Я использую ключевое слово, когда обнаруживаю, что тип не дает много дополнительной информации.

  • Главным образом в циклах foreach , которые я узнал от Resharper, как это там. Большую часть времени вы знаете, какой тип коллекции вы просматриваете, поэтому вы знаете, что ожидаете элементы из этой коллекции.
  • Linq запросы . Результатом запросов linq часто являются очень сложные универсальные типы. Отображение этого типа приносит больше вреда, чем пользы.
  • Длинные имена, которые просто инициализируются их конструктором. Вы уже можете сказать, что это за тип, посмотрев на конструктор.

В качестве примера для последнего утверждения:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();
Стивен Джеурис
источник
24
Последний пример - именно то, когда ключевое слово var может быть лучше. Представьте, что код замусорен в вашем коде. Factory.CreateSomeTypeвозвращается IEnumerable<SomeType>. Однажды, по какой-то причине, он меняется, чтобы вернуться SomeType[]. Если вы использовали var, это просто перекомпиляция.
ПДР
1
Получил этот пример неправильно, а затем пошел искать еду. Numpty! Лучшим примером будет использование твоего. Что делать, если Factory.CreateSomeType()изменения, чтобы вернуть ISomeType?
фунтовые
4
@pdr: это, скорее всего, означает, что интерфейс также изменился, и поведение также должно быть скорректировано / добавлено. Если это простое переименование, у вас, конечно, есть автоматическое переименование. Если «контракт» изменяется, я скорее вижу, что мой код нарушается, и я могу видеть, должен ли я что-то корректировать или нет.
Стивен Джеурис
2
Я думаю, что гораздо более вероятно, что если возвращение конкретного типа становится возвращением интерфейса, который он просто учитывает для других конкретных типов с тем же интерфейсом (в соответствии с шаблоном Factory). Но если контракт действительно изменится, ваш код будет нарушен - хотя вы можете обнаружить, что он нарушается только в нескольких случаях, когда это важно, а не везде.
фунтовые
1
@ Том Хотин, мы все знаем, что неизбежно избегать nullполностью. Кроме того, чем больше я ищу альтернатив null, тем больше я понимаю, что использование nullиногда является самым чистым решением. Мой приведенный пример не так уж и плох, ИМХО, и я считаю его подходящим использованием обнуляемых типов.
Стивен Джеурис
16

var позволяет меньше подробного кода, что повышает удобочитаемость. По моему мнению, читаемость должна измеряться не тем, сколько деталей вы видите, а тем, сколько деталей скрыто на первый взгляд. Помимо примеров Linq, var позволяет вводить утки на уровне исходного кода, учитывая следующий пример:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Кому интересно, что это за тип метки, если она предоставляет свойство Text?

Codism
источник
Кто-то пытается понять, является ли это, например, меткой winforms или меткой WPF.
Стивен Джеурис
14
@ Steven Jeuris: обычно это известная контекстная информация. Если нет, то вы неверно подходите к коду.
Кодизм
Кто-то, кто хочет знать, является ли это меткой WPF по умолчанию или какой-то другой? :)
Стивен Джеурис
14
1. Должен ли этот человек действительно заботиться, если это метка со свойством Text? 2. Если это один из редких случаев, когда ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО ДЕЙСТВУЕТСЯ УКАЗАНО, чтобы позаботиться о них, спросите Intellisense. 3. Если они редактируют код в IDE без Intellisense, они, вероятно, имеют гораздо большие неудобства, чем 'var' :)
KutuluMike
4
Кто-то с плохим чувством абстракции.
Джим Балтер
16

У меня нет серьезных комментариев по поводу ?? оператора, так как я никогда не использовал язык с таким оператором интенсивно. Что касается varлюдей, то они программируют на таких языках, как Ruby, Python, Perl и PHP, которые все время имеют полностью неявную типизацию. Уроженцы этих языков понимают, что формальный тип переменной обычно не имеет никакого отношения к шуму. Вас больше интересует, что может сделать переменная , то есть ее структурный / утиный интерфейс.

Точно так же я программирую в основном на D. D имеет статическую типизацию, но имеет auto ключевое слово, эквивалентное var. Считается идиоматичным использовать его везде, если только вы не видите особой необходимости подчеркивать тип чего-либо для читателя или (посредством неявного преобразования) компилятора. За исключением случая, когда он используется в качестве возвращаемого типа функции (это разрешено в D), я никогда не считал, что это затрудняет читабельность, потому что я в основном думаю о структурных / утиных интерфейсах, а не формальных / номинативных типах, когда я программирую.

Кроме того, IMHO использование varвезде, где это возможно, является хорошим примером СУХОГО. Тип чего-либо должен быть указан в одном и только одном месте, а затем автоматически распространяться всякий раз, когда это необходимо распространять. Если вы используете varи формальный тип переменной должен измениться в какой-то момент, необходимые изменения будут автоматически распространяться везде, где это необходимо компилятору, если программа все еще корректна по типу, а не программисту, который должен вручную изменять каждый экземпляр , Это хорошая вещь (ТМ).

dsimcha
источник
13

Я думаю, что это вопрос для команды в конце концов. Если он не доступен для чтения кому-либо еще в моей команде, я не буду его использовать, хотя я мог бы пару раз попытаться убедить их примерами или указать на анагональные сокращения (такие как + =), которые они считают более читабельными.

Однако если работать в одиночку, то я нахожу и вар в высшей степени читабельный без ограничений. Четное

var a = b ?? c ?? d ?? e ?? "";

это довольно однозначно для меня.

Тернарные операторы и dynamicдругое дело, конечно.

прецизионный самописец
источник
4
Я бы использовал `String.Empty 'здесь.
Работа
1
@ Job, честно говоря, я тоже. Я собирался положить что-то в эту строку, а потом ничего не мог придумать :)
pdr
4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Ли Лувьер
2
@Xaade Ты никогда не будешь достаточно уверен. Но на самом деле использование String.Empty или "" - это личное предпочтение. Я использую "", потому что это короче ...
Карра
12
@Xaade - если String.Emptyкогда-нибудь вернется null, нас ждет чертовски много неработающего кода.
Джесси С. Slicer
10

Аргумент за использование ?? Оператор был, он забирает читабельность в коде.

Кратко подумав об этом, этот комментарий говорит мне, что человек, делающий комментарий, не понимает его так, как он / она должен. Скорее всего, это верно в определенных ситуациях, но в целом я не сбрасываю со счетов то, что команда C # явно сочла достаточно важным, чтобы добавить его из-за «читабельности». Я положил это в той же категории if(boolean_object)против if(boolean_object == true). Некоторые люди утверждают, что второй более читабелен, но на самом деле он просто добавляет дополнительный код для чтения / ввода, а в некоторых ситуациях может быть более запутанным (думаю if(boolean_object != false))

Мой вопрос: разве не происходит то же самое, когда вы начинаете использовать var?

Команда C # позволила вам не определять то, что вы знаете, что это будет. Если мне абсолютно не нужно определять, какой будет переменная (либо абсолютно важно, чтобы возвращаемый объект имел тип x, либо он действительно не читался), я использую var. var x = "MY_STRING";Я знаю, что это строка, когда я смотрю на нее. По правде говоря, мне все равно, что это строка, если она делает то, что мне нужно. Определение типа переменной для меня, а не для компилятора. Если что-то не так, компилятор сообщит мне, когда он запустится, если у меня неправильный тип переменной.

kemiller2002
источник
0

varКлючевое слово, на мой взгляд, взял верх используется в ситуациях , для которых он был введен оригинальный - LINQ запросы. В этих запросах тип возвращаемого результата часто имеет какое-то большое запутанное имя, которое трудно определить заранее и не помогает читателю понять, что делает ваш код.

Однако делать var text = "Some text " + variableName + "some more text."это просто лениво.

РЕДАКТИРОВАТЬ: @Jorg Вы вскочили на намеренно упрощенный ответ, но ничего не добавили к обсуждению. Хорошо, как об этом для лучшего примера: var items = doc.DocumentElement.FirstChild.ChildNodes;если вы сможете выяснить тип из этого, я дам вам печенье.

Джош Эрл
источник
18
Если вы не можете понять, что "Some text "это string, то у вас есть гораздо более серьезные проблемы, чем количество vars в вашем коде.
Йорг W Mittag
3
Проблема не в этом var; проблема в дерьмовом имени переменной "items". Если вы используете хорошее имя переменной, в этом нет ничего плохого var.
Kyralessa
3
Я предполагаю (не глядя), что элементы - это коллекция узлов XML, которые, как я ожидаю, будут иметь все свойства и методы коллекции узлов XML, и это действительно все, что мне нужно знать.
KutuluMike
Если вам нужно знать, какой тип обозначает var, и вы не можете сразу определить это, просто наведите на него курсор мыши. Не нужно много думать, чтобы сделать это.
scrwtp
1
«просто ленивый» - это не аргумент против этого. На самом деле, это совсем не разумно.
Джим Балтер
0

У меня есть фундаментальная проблема с использованием var.

В этом примере все бок о бок, но проблема действительно в больших решениях с общими библиотеками или проектами.

Учти это:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Что произойдет, если GetMeAnObject будет изменен кем-то другим в соответствии с их потребностями?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

Метод MainProgram будет иметь большую красную ошибку при .PerformOperation (). Что произошло? PerformOperation отлично работал раньше. Мы смотрим на методы объекта, и он просто исчезает без следа. Это было там в прошлый раз, и нам нужен этот метод. Вы могли бы потратить много времени, преследуя свой хвост и пытаясь выяснить, почему, если MyFirstObject имеет метод PerformOperation, его теперь нельзя увидеть. Все «знают», что GetMeAnObject возвращает MyFirstObject, поэтому нет смысла проверять это.

Если бы вы явно ввели theObject, то в строке, которая вызывает GetMeAnObject, возникла бы ошибка Invalid Cast, и было бы ослепительно очевидно, что GetMeAnObject возвращает тип, который отличается от ожидаемого.

Короче говоря, явное объявление означает, что вы знаете, что означают ошибки. Неверное приведение означает, что вы ожидали один тип, а другой тип был возвращен. Нераспознанный участник означает, что участник был не распознан.

Хью Феникс-Халм
источник
10
Сотрудник произвел серьезное изменение в коде, не покрытом тестами, и вы думаете, что проблема в этом var? Нельзя ожидать, что язык защитит от такого поведения - что если бы они изменили MyFirstObject напрямую? Это все еще сломалось бы, но никакой синтаксис не мог бы вас спасти от этого. Я бы даже посчитал это сильным var: что если вместо возврата MySecondObject вы теперь вместо этого возвращаете IMyFirstObject?
Phoshi
2
«Все« знают », что GetMeAnObject возвращает MyFirstObject, так что нет смысла проверять это». На самом деле я не могу придумать сценарий в программировании, где я на самом деле зависел бы от того, что такое GetMeAnObject, если я отлаживаю. Если бы я проверил, что PerformOperation не существует, я бы увидел код, и нет, это для другого класса. Если в IDE класс будет всплывать экземпляр, я смотрю на тип объекта. На самом деле, когда компилятор сообщает мне об ошибке, он говорит «у класса MySecondObject нет операции PerformOperation». Как это всем известно?
Мухаммед Алкарури