2012-03-28 2 views
4

Я считаю, что это частично связано с короткозамкнутой логикой, но я не мог найти никаких вопросов, которые непосредственно отвечали на мой вопрос. Возможные сопутствующие вопросы: Benefits of using short-circuit evaluation, Why use short-circuit code?Есть ли преимущества для быстрого выхода из метода или конструктора?

Рассмотрим следующие два кодовых блоков, оба из которых являются возможные конструкторы класса

public MyClass(OtherClass other){ 
    if (other != null) { 
     //do something with other, possibly default values in this object 
    } 
} 

и это

public MyClass(OtherClass other){ 
    if (other == null) return; 

    //do something with other, possibly default values in this object 
} 

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

ответ

6

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

+0

Это была моя мысль. Просто хотелось посмотреть, была ли производительность (или какая-либо другая) польза для этого в одном направлении против другого. –

4

Единственная разница - читаемость. С помощью того, что вы называете «быстрым выходом», вы можете перестать думать о том, какое условное вы внутри, потому что вы больше не внутри.

3

Последнее, как правило, легче читать, и если у вас есть несколько случаев, в которых вы заканчиваете, тогда это становится еще проще. Однако разницы в скорости нет.

Предположим, у вас есть функция, которая принимает в Int32? и выходит, если значение либо null, even, или больше, чем 100.

Вы могли бы сделать

void fn(Int32? num) { 
    if (num != null) { 
     if (num < 100) { 
      if (num % 2 != 1) { 
       //method code 

или что-то вроде

void fn(Int32? num) { 
    if (num == null) 
     return; 

    if (num > 100) 
     return; 

    if (!(num % 2 != 1)) 
     return; 

    //method code 

Теперь пример немного глупый, я могу слышать вас сейчас, Почему бы не поместить их всех на одну строку вместе w с || или && и в этом случае да. Но представьте себе, если проверка данных была намного сложнее? В итоге вы получите чрезмерное отступы, гораздо труднее прочитать код.

0

Это все о читаемости и согласованности в вашей базе кода. Длинный метод с возвращенными посыпками по всему тексту будет трудно читать (но тогда длинный метод все равно плохой). Пара предложений охраны в начале метода может улучшить ясность и удалить ненужное гнездование. Однако в конкретном примере, который вы указали, вам нужно спросить: «Почему здесь пусто?» Должны ли вы выбросить исключение или вместо этого перейти в null objects?

+0

в этом конкретном случае, нуль - это хорошо, потому что они являются конструкторами удобства для моделей просмотра в asp.net mvc. Если модель базы данных с уровня сервиса возвращается как нуль (хорошая возможность для создания версии «Сохранить»), модель представления будет пустой, и это поможет уменьшить код контроллера, всегда создавая экземпляр модели представления, независимо от того, модель базы данных равна нулю. –

0

Считываемость - самая большая разница. В этом случае последнее приводит к уменьшению отступов, которые некоторые могут считать более читаемыми. Я также знаю несколько разработчиков, которые твердо убеждены, что методы должны иметь только один оператор return. Эти разработчики, очевидно, предпочли бы прежние.

1

В частности, для этого случая, в то время как вы (при условии, что вы являетесь человеком), необходимо прочитать оставшуюся часть исходного кода, чтобы добраться до конца метода, процессор этого не делает. Оператор блока if в первом примере оценивает условие, и если он оценивает значение false, выполнение просто переходит к концу метода.

1

Я попытался с помощью этого конструктора

public AnotherExpense(string param) 
    { 
     if (param != null) 
     { 
      Console.WriteLine("test"); 
     } 
    } 

IL код

.method public hidebysig specialname rtspecialname 
    instance void .ctor(string param) cil managed 
{ 
    // Code size  20 (0x14) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: call  instance void AccountParserCSV.Expense::.ctor() 
    IL_0006: ldarg.1 
    IL_0007: brfalse.s IL_0013 
    IL_0009: ldstr  "test" 
    IL_000e: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0013: ret 
} // 

если вы измените его на

public AnotherExpense(string param) 
    { 
     if (param == null) 
      return; 

      Console.WriteLine("test"); 
    } 

вы получаете

.method public hidebysig specialname rtspecialname 
    instance void .ctor(string param) cil managed 
{ 
    // Code size  21 (0x15) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: call  instance void AccountParserCSV.Expense::.ctor() 
    IL_0006: ldarg.1 
    IL_0007: brtrue.s IL_000a 
    IL_0009: ret 
    IL_000a: ldstr  "test" 
    IL_000f: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0014: ret 
} 

посмотреть «разницу» в строке 7? ;-) Редактировать - скомпилировано в 'Release' с VS2010

+0

Я вижу разницу (один оценивает против true, другой false), но я точно не следую потоку MSIL здесь (довольно неопытный при чтении). Похоже, что последний оценивает еще одну «линию», так как это два возвратных оператора, но единственное отличие - это GOTO на 007? –

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