2010-11-03 3 views
18

Приемлемо/хороший стиль, чтобы упростить эту функцию:если/другое, хороший дизайн

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    if (obj.CanDo(type)) 
    { 
     return Do(obj); 
    } 
    else 
    { 
     return false; 
    } 
} 

как:

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    return obj.CanDo(type) && Do(obj); 
} 

Второй вариант короче, но, возможно, менее интуитивным.

+17

Что бы ни было легко читать и поддерживать, это «лучший» способ. – dotariel

+12

Это зависит: http://blogs.msdn.com/b/ericlippert/archive/2010/02/01/style-follows-semantics.aspx – jason

+1

@ XSaint Хорошая работа, заявляющая очевидное, теперь реальный вопрос: какой из них легче читать и поддерживать. Последнее очень хорошо объяснено в ссылке Джейсона! –

ответ

64

Что бы код:

return obj.CanDo(type) ? Do(obj) : false; 
+2

Право, третий вариант. –

+6

Это лучший ответ. Он короткий, но эквивалентный if/else (не просто функционально эквивалентный, но семантически). Единственная критика, которую я имею, это то, что я удалю лишние круглые скобки. – Timwi

+13

Это гладкое и приятное однострочное решение, но не очень читаемое. – Zannjaminderson

1

Никогда не делайте этого. Держите его простым и интуитивно понятным.

+1

Второй код * является простым и интуитивно понятным. Если вы не согласны, пожалуйста, объясните. –

+0

прост, как легко понять и поддерживать –

+0

@ Liviu: ну тогда: код * * легко понять и поддерживать. Если вы не согласны, пожалуйста, объясните. –

24

Версия с кронштейнами:

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    if (obj.CanDo(type)) 
    { 
     return Do(obj); 
    } 

    return false; 
} 

или версия без скобок (в ответе комментарии высокие дебаты по этому поводу):

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    /* 
    * If you want use this syntax of 
    * "if", this doing this on self 
    * responsibility, and i don't want 
    * get down votes for this syntax, 
    * because if I remove this from my 
    * answer, i get down votes because many 
    * peoples think brackets i wrong. 
    * See comments for more information. 
    */ 
    if (obj.CanDo(type)) 
     return Do(obj); 

    return false; 
} 

Вашего первый пример кода лучше , но я думаю, что моя версия еще лучше.

+4

Мне нравится эта версия лучше. Вы также можете удалить фигурные скобки из if -block, чтобы свести его немного больше, но некоторым людям это очень не нравится. – CodexArcanum

+1

@CodexArcanum: да, мне это не нравится – Svisstack

+0

@Svisstack: можете ли вы дать аргументы, чтобы оправдать последнее предложение? Я думаю, что это неправильно. –

5

В этом случае, я бы с первым вариантом - это гораздо более читаемым и намерение код гораздо понятнее.

+3

Остальное не нужно. –

6

1-й вариант гораздо легче читать с меньшим шансом быть непонятым, и я думаю, что это важно в коде реального мира.

18

else бесполезен, и &&, как бы это ни было очевидно, не так читается, как чистый текст.

Я предпочитаю следующее:

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    if (obj.CanDo(type)) 
    { 
     return Do(obj); 
    } 
    return false; 
} 
+0

+1 Я как раз собирался опубликовать этот точный метод. Я ненавижу, когда все возвраты вложены. Это делает менее очевидным, что он «всегда» возвращает что-то, esp для компилятора. –

13

Да.

Особенно с именами, похожими на выбранные имена, т.е. CanDoSomething и DoSomething это совершенно ясно любому компетентному программисту, что второй код делает: «тогда и только тогда, когда условие выполняется, сделать что-то и вернуть результат ». «Тогда и только тогда, когда» является основным значением короткозамкнутого оператора &&.

Первый код свернут и излишне длинный, не указав больше информации, чем второй код.

Но в целом два условия не могут образовывать такие близкие отношения (как в CanDo и Do), и, возможно, было бы лучше их логически отделить, потому что помещение их в один и тот же условный порядок может не иметь интуитивного смысла.

Многие люди заявляют, что первая версия «намного понятнее». Я бы очень хотел услышать их аргументы. Я не могу думать ни о чем.

С другой стороны, есть это тесно связано (хотя и не вполне тот же код):

if (condition) 
    return true; 
else 
    return false; 

это должно всегда быть преобразованы к этому:

return condition; 

Нет исключение. Это краткое и более читаемое для того, кто компетентен на этом языке.

+4

Да, но OP хочет вернуть что-то еще, а не результат результата. – Svisstack

+0

Многие программисты не полностью компетентны, многие из них должны иметь дело с несколькими языками со временем, когда логические операторы иногда обрабатываются по-разному. По этой причине, я думаю, что второй блок более безопасен, если не яснее. – kaliatech

+4

@ kaliatech: есть длинный выстрел между тем, чтобы быть «полностью компетентным» и понимать основы языка. И я утверждаю (сильно!), Что мы не всегда можем обслуживать новичков в чистом коде, потому что результат будет запутанным, сложным и в конечном итоге тяжелым для профессионалов. Если не по какой-либо другой причине, то из-за явного размера кода. Да, размер кода * делает * значение. –

7

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

bool TryDo(Class1 obj, SomeEnum type) { 
    return obj.CanDo(type) ? Do(obj) : false; 
} 
+3

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

+0

(это может зависеть от языка, но) Я считаю, что правильным термином для этого является «тернарный оператор» –

+0

@John Isaacks: Термин «тернарный оператор» указывает только, что это оператор, который имеет три операнда, тогда как термин «условный оператор» точно определяет, какой именно оператор. В C# существует только один оператор с тремя операндами, но я все же считаю более полезным использовать термин, описывающий работу оператора, а не только то, сколько операторов он использует. См. Также: http://en.wikipedia.org/wiki/Ternary_operation – Guffa

6

мне не нравится этот дизайн, и, возможно, не по той очевидной причине. Меня это беспокоит. return Do (obj); Для меня нет смысла, чтобы функция Do имела тип возврата bool. Является ли это заменой ошибок, вызывающих ошибку? Скорее всего, эта функция должна быть недействительной или возвращать сложный объект. Сценарий просто не должен появляться. Также, если bool как-то имеет смысл сейчас, он может легко перестать иметь смысл в будущем. С изменением кода вам потребуется больше исправлять ошибки

+0

хороший момент, спасибо –

+3

Абсолютно не согласен. Метод, который имеет побочные эффекты и возвращает bool, абсолютно нормален и постоянно появляется. Рассмотрим, например, 'bool HashSet .Add()'. Ваша критика делает слишком много предположений о структуре кода OP - из того, что мы мало что видели, это вполне разумно. – Timwi

+0

-1, см. Комментарий Timwi –

12

Укороченная версия скрывает тот факт, что Do делает что-то. Похоже, вы просто делаете сравнение и возвращаете результат, но вы на самом деле делаете сравнение и выполняете действие, и не очевидно, что код имеет этот «побочный эффект».

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

+1

Еще одна причина выбора хороших имен методов. Если имена методов понятны, как в примере, то факт, что 'Do' делает что-то, очень сложно скрыть. Кроме того, в коде отсутствует * сравнение *. –

+0

Сравнение, вероятно, было немного ленивым, я вам даю, хотя && эффективно делает немного мудрый сравнения, поэтому ... Я согласен, что имена методов, безусловно, помогут, но я все равно считаю это рефактором слишком далеко –

+1

«побитовое сравнение»? Что это? Нет инструкции IL, которая обычно описывается именно так. И '? : 'и' && 'только компилируются в инструкцию' brtrue' или 'brfalse', а не' bgt', 'beq' и т. д., и, конечно же, не что-то, что обычно называют« поразным »(например,' и ', что не является сопоставлением, а является арифметической инструкцией). – Timwi

4

Хотя, безусловно, ясно, что второй код для грамотного программиста, мне показалось бы более понятным и понятным в более общем случае, чтобы написать код, как и любой другой, «если условие выполнено, выполните действие, иначе не пройдете».

Это может быть достигнуто либо путем:

return obj.CanDo(type)? Do(obj) : false; 

Или,

if(obj.CanDo(type)) return Do(obj); 
return false; 

Я считаю это выше, потому что этот же стиль может быть воспроизведен независимо от типа возврата. Например,

return (array.Length > 1)? array[0] : null; 

Или

return (curActivity != null)? curActivity.Operate() : 0; 

Тот же стиль также может быть расширена до ситуаций, которые не имеют возвращаемого значения:

if(curSelection != null) 
    curSelection.DoSomething(); 

Мои два цента.

1

я мог бы получить ненависть за это, но как насчет:

if (obj.CanDo(type)) return Do(obj); 
return false; 

Я не люблю, когда брекеты лайнеры.

+0

Это не только избыточное, но и очень трудно читать. – TimC

+0

@CrapHands Удалено другое, хотя для меня это делает его немного менее удобочитаемым, так как мой мозг в основном добавляет туда что-то еще. – Radu

+0

Мне не нравится помещать затем часть if в ту же строку, что и if. Просто добавьте рубеж до 'return DO()' – CodesInChaos

1

Я думаю, что Class1 Type должен определить, может ли он это сделать, учитывая значение SomeEnum.

Я хотел бы оставить решение о том, может ли она справиться вход для того, чтобы решить:

bool TryDo(Class1 obj, SomeEnum type) 
{ 
    return obj.Do(type));  
} 
+0

Но тогда потеряет вызов Do (obj) – KevinDTimm

+0

@KevinDTimm Правильно, я имел в виду вернуть return obj.Do (type)); obj должен решить, может ли он выполнить или не выполнить задачу, вернуть false, иначе – TimC

1

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

4

Мне не нравится вторая версия, так как я не являюсь поклонником порядка оценки подвыражений в условном выражении. Он помещает ожидаемый заказ на подвыражения, которые, на мой взгляд, должны иметь равный приоритет (хотя они и не делают).

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

3

IMO это только ОК, если вторая функция не имеет побочных эффектов. Но поскольку Do() имеет побочные эффекты, я бы пошел с if.

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

См. Eric Lippert's Blog для более подробного объяснения.

3

Проблема побочного эффекта, которую некоторые люди упоминают, является фиктивной. Никто не должен удивляться тому, что метод «Do» имеет побочный эффект.

Дело в том, что вы вызываете два метода. Оба эти метода имеют bool как возвращаемое значение. Ваш второй вариант очень ясный и лаконичный. (Хотя я бы избавиться от внешней скобки и вы забыли концовки запятой.)

1

No. Второй версия

return (obj.CanDo(type) && Do(obj)) 

зависит от поведения короткого замыкания на & & оператора, который оптимизация, а не метод управления потоком программы. На мой взгляд, это немного отличается от использования исключений для потока программы (и почти так же плохо).

Я ненавижу умный код, это сука, чтобы понимать и отлаживать. Целью функции является «если мы сможем это сделать, тогда сделаем это и вернем результат, иначе возвращаем false». Исходный код делает это очень понятным.

+0

вы неправильно поняли цель короткого замыкания. Это * не * прежде всего оптимизация (если вообще, это просто побочный эффект). Следовательно, весь ваш аргумент неверен. –

+0

@ Konrad - что ты говоришь это? Это, безусловно, оптимизация, я предполагаю, что она была предназначена как таковая, но не знаю. Я уверен, что он не предназначен для управления потоком программ. –

5

Ни то, что, когда TryDo возвращает False, вы не можете определить, было ли это потому, что 'Not CanDo' или 'Do False'.

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

Если результат не имеет смысла, цель будет понятнее с

void TryDo(Class1 obj, SomeEnum type) 
{ 
    if (obj.CanDo(type)) 
     Do(obj); 
    return; 
} 

Если результат действительно имеет значение, то должно быть так, чтобы различать между двумя «ложными» возвращается. И.Е. Что означает «If (! TryDo (x))» означает?

Edit: Для того, чтобы поместить это иначе, код OP является говоря, что «я не умею плавать» так же, как «я пытался плавать и утонул»

+0

Мне нравится этот ответ! – fearofawhackplanet

1

Есть несколько хороших ответов уже, но я подумал, что я покажу еще один пример (что я считаю) хорошего, читаемого кода.

Держат или удаляем фигурные скобки назад по корпусу инструкции if в соответствии со вкусом.

Мне нравится этот подход, поскольку он показывает, что результат false если что-то еще не происходит, и я думаю, что это более ясно показывает, что Do() делает что-то и возвращает логическое значение, которое TryDo() использует в качестве возвращаемого значения.

+0

Я согласен с тобой! В то же время он позволяет вам установить возвращаемое значение «по умолчанию» и иметь одну точку выхода, которую также будет очень легко отлаживать –

Смежные вопросы