Да, важно, чтобы ваш элемент использовался как ключ в словаре, или HashSet
и т. д. - поскольку он используется (при отсутствии пользовательского IEqualityComparer
) для группировки элементов в ведра. Если хэш-код для двух элементов не соответствует, они могут never считаться равными (Equals
просто никогда не будет вызываться).
Метод GetHashCode()
должен отражать логика Equals
; следующие правила:
Equals(...) == true
), то они должны возвращать одно и то же значение для GetHashCode()
GetHashCode()
равен, для них необходимо не , чтобы они были одинаковыми; это столкновение, и Equals
будет вызываться, чтобы убедиться, что это реальное равенство. В этом случае это выглядит так: «return FooId;
» является подходящим GetHashCode()
. Если вы тестируете несколько свойств, обычно их объединяют с использованием кода, как показано ниже, для уменьшения диагональных столкновений (т. Е. Для new Foo(3,5)
имеет другой хеш-код для new Foo(5,3)
):
int hash = 13;
hash = (hash * 7) + field1.GetHashCode();
hash = (hash * 7) + field2.GetHashCode();
...
return hash;
Ох - для удобства вы можете также рассмотреть возможность предоставления операторов ==
и !=
при переопределении Equals
и GetHashCode
.
Демонстрация того, что происходит, когда вы ошибаетесь здесь .
Эти конструкции могут часто заменяться полиморфизмом. Это даст Вам короче и менее хрупкому коду.
Естественно, этот вопрос является языковозависимым, но оператор переключения мог бы быть более оптимальным вариантом во многих случаях. Хороший C или компилятор C++ смогут генерировать таблица переходов , которая будет значительно быстрее для больших наборов случаев.
Если у Вас действительно должен быть набор того, если бы тесты и хотят сделать, разные вещи whenwver тест верны, что я рекомендовал бы некоторое время цикл только с IFS - нет еще. Каждый, если делает тест вызовы метод затем, убегает из цикла. Нет еще нет ничего худшего, чем набор сложенного if/else/if/else и т.д.
Я расцениваю, они если-lseif-... создают как "шум ключевого слова". В то время как может быть ясно, что это делает, этому недостает краткости; я рассматриваю краткость как важную часть удобочитаемости. Большинство языков обеспечивает что-то как switch
оператор. Создание карты является способом получить что-то подобное на языках, которые не имеют такого, но, конечно, похоже на обходное решение, и существует немного служебное (оператор переключения переводит в некоторых простых, сравнивают операции и условные переходы, но карта сначала создается в памяти, затем запросила, и только затем сравнивание и переход происходят).
В языке Common LISP, существует две встроенные конструкции переключателя, cond
и case
. cond
позволяет произвольные условные выражения, в то время как case
только тесты для равенства, но более кратко.
(cond ((= i 1) (do-one)) ((= i 2) (do-two)) ((= i 3) (do-three)) (t (do-none)))(case i (1 (do-one)) (2 (do-two)) (3 (do-three)) (otherwise (do-none)))
, Конечно, Вы могли сделать свое собственное case
- как макрос для Ваших потребностей.
В Perl, можно использовать for
оператор, дополнительно с произвольной маркировкой (здесь: SWITCH
):
SWITCH: for ($i) {
/1/ && do { do_one; last SWITCH; };
/2/ && do { do_two; last SWITCH; };
/3/ && do { do_three; last SWITCH; };
do_none; };
Метод Карты о лучшем существует. Это позволяет Вам инкапсулировать операторы и разбивает вещи вполне приятно. Полиморфизм может дополнить его, но его цели немного отличаются. Это также представляет ненужные деревья класса.
Переключатели имеют недостаток пропавших без вести операторов завершения и проваливаются и действительно поощряют не повреждать проблему в мелкие кусочки.
, Что быть сказанным: маленькое дерево если.. else's прекрасен (на самом деле, я спорил за в течение многих дней о, имеют 3 если.. elses вместо того, чтобы недавно использовать Карту). Когда Вы начинаете помещать более сложную логику в них, что это становится проблемой из-за пригодности для обслуживания и удобочитаемости.
В Python я написал бы Ваш код как:
actions = {
1: doOne,
2: doTwo,
3: doThree,
}
actions[i]()
Я сказал бы даже, что никакая программа еще никогда не должна использовать. Если Вы делаете Вы напрашиваетесь на неприятности. Вы никогда не должны принимать, не является ли это X, это должен быть Y. Ваши тесты должны протестировать на каждого индивидуально и сбой после таких тестов.
switch
оператор или классы с виртуальными функциями как необычное решение. Или массив указателей на функции. Это, все зависит от того, как сложные условия, иногда нет никакого пути вокруг тех if's. И снова, создание серии классов для предотвращения одного оператора переключения является явно неправильным, код должен быть максимально простым (но не более простым)
Я использую следующую стенографию только для забавы! Не пробуйте anyof они, если код clearity касается Вас больше, чем количество введенных символов.
Для случаев, где doX () всегда возвращает true.
i==1 && doOne() || i==2 && doTwo() || i==3 && doThree()
Ofcourse я пытаюсь удостовериться, чтобы большинство пустых функций возвратилось 1 просто, чтобы гарантировать, что эти стенографии возможны.
можно также обеспечить присвоения.
i==1 && (ret=1) || i==2 && (ret=2) || i==3 && (ret=3)
Как instad записи
if(a==2 && b==3 && c==4){
doSomething();
else{
doOtherThings();
}
Запись
a==2 && b==3 && c==4 && doSomething() || doOtherThings();
И в случаях, где не уверенный, что возвратит функция, добавляют || 1 :-)
a==2 && b==3 && c==4 && (doSomething()||1) || doOtherThings();
я все еще нахожу, что он быстрее вводит, чем использование всех их если еще и он верные волнения все новые новички. Вообразите полную страницу оператора как это с 5 уровнями расположения с отступом.
, "если" редко в некоторых моих кодах и я дал ему имя "при программировании" :-)
В этом простом случае Вы могли использовать переключатель.
Иначе основанный на таблице подход выглядит хорошо, это был бы мой второй выбор каждый раз, когда условия являются достаточно регулярными для создания этого применимым, особенно когда количество случаев является большим.
Полиморфизм был бы опцией, если нет слишком многих случаев, и условия и поведение неправильны.
В парадигме OO Вы могли сделать это с помощью старого доброго полиморфизм . Слишком большой, если - еще структуры или конструкции переключателя иногда считают запахом в коде.
switch (i) {
case 1: doOne(); break;
case 2: doTwo(); break;
case 3: doThree(); break;
default: doNone(); break;
}
вводивший это, я должен сказать, что нет так много, неправильного с Вашим если оператор. Как сказанный Einstein: "Сделайте его максимально простым, но не более простым".
В зависимости от типа вещи Вы то, если.. else'ing, рассмотрите создание иерархии объектов и использования полиморфизма. Как так:
class iBase
{
virtual void Foo() = 0;
};
class SpecialCase1 : public iBase
{
void Foo () {do your magic here}
};
class SpecialCase2 : public iBase
{
void Foo () {do other magic here}
};
Затем в Вашем коде просто называют p->, Foo () и правильная вещь произойдет.
Пример, данный в вопросе, достаточно тривиален для работы с простым переключателем. Проблема возникает, когда если-elses вкладываются глубже и глубже. Они больше не "ясны или легки читать", (как кто-то еще обсужденный) и добавление нового кода или исправление ошибок в них становится все более трудным и более твердым быть уверенным в том, потому что Вы не могли бы закончить, где Вы ожидали, сложна ли логика.
я видел, что это происходит много времен (переключатели вкладывали 4 уровня глубоко и сотни строк долго - невозможный поддержать), особенно в классах фабрики, которые пытаются сделать слишком много для слишком многих различных несвязанных типов.
, Если значения Вы выдерживаете сравнение с, не бессмысленные целые числа, но некоторый уникальный идентификатор (т.е. перечисления использования как полиморфизм бедного человека), затем Вы хотите использовать классы для решения проблемы. Если они действительно - просто числовые значения, то я использовал бы отдельные функции для замены содержания, если и еще блоки, и не разрабатывают некоторую искусственную иерархию классов для представления их. В конце, который может привести к более грязному коду, чем исходные спагетти.
переключатель оператор, конечно, намного более симпатичный затем все они if's и else's.
Существует две части к тому вопросу.
, Как для диспетчеризации на основе значения? Используйте оператор переключения. Это отображает Ваше намерение наиболее ясно.
, Когда для диспетчеризации на основе значения? Только в одном месте на значение: создайте полиморфный объект, который знает, как обеспечить ожидаемое поведение для значения.
На Объектно-ориентированных языках распространено использовать полиморфизм для замены if's.
мне понравился этот Google Clean Code Talk, который покрывает предмет:
Чистые Переговоры по Коду - Наследование, Полиморфизм, & при Тестировании
КРАТКИЙ ОБЗОР
Является кодом, полным если операторы? Операторы переключения? У Вас есть тот же оператор переключения в различных местах? При внесении изменений, Вы вносите то же изменение в то же если/переключатель в нескольких местах? Вы когда-либо забывали тот?
Этот разговор обсудит подходы к использованию Объектно-ориентированных методов для удаления многих из тех условных выражений. Результатом является более чистый, более трудный, лучший разработанный код, который это легче протестировать, понять и поддержать.
Оператор переключения:
switch(i)
{
case 1:
doOne();
break;
case 2:
doTwo();
break;
case 3:
doThree();
break;
default:
doNone();
break;
}
За пределами использования оператора переключения, который может быть быстрее, ни один. Если Еще ясно и легок читать. необходимость искать вещи в карте запутывает вещи. Почему делают код тяжелее для чтения?
Используйте переключатель/случай, это более чисто :p