2013-12-23 6 views
5

Итак, я обсуждал с коллегой преимущества ReSharper (в настоящее время v8.1) с точки зрения рефакторинга if/else, если инструкции для переключения операторов. Я не думал об этом, но мой коллега придумал пример ниже. Дело в том, что, когда код запускается, вы можете видеть, что он фактически переходит к «else» в DoElseIf, но не в DoSwitch. Несмотря на это, ReSharper предполагает, что я реорганизую my if/else, если оператор switch, когда очевидно, что скомпилированный код не ведет себя одинаково.ReSharper: if/else if vs switch in C#

Может ли кто-нибудь, у кого больше знания ReSharper, чем я, скажите мне, если я смотрю на это неправильно или если я должен быть осторожным рефакторинг if/else, если оператор switch?

Вот код:

namespace ConsoleApplication1 
{ 
    class Program 
    { 
      static bool MyValue { get; set; } 
      static void Main(string[] args) 
      { 
       Task t = new Task(ChangeIt); 
       t.Start(); 

       for (var i = 0; i < 1000000; i++) 
       { 
         DoElseIf(); 
       } 
       for (var i = 0; i < 1000000; i++) 
       { 
         DoSwitch(); 
       } 

       Console.WriteLine("Work's done!"); 
       Console.ReadLine(); 
      } 

      static void DoSwitch() 
      { 
       switch (MyValue) 
       { 
         case true: 
           //Console.WriteLine("true"); 
           break; 
         case false: 
           //Console.WriteLine("false"); 
           break; 
         default: 
           Console.WriteLine("WTF (Switch)!"); 
           break; 
       } 
      } 

      static void DoElseIf() 
      { 
       if (MyValue == true) 
       { 
         //Console.WriteLine("true"); 
       } 
       else if (MyValue == false) 
       { 
         //Console.WriteLine("false"); 
       } 
       else 
       { 
         Console.WriteLine("WTF (Else-if)!"); 
       } 
      } 

      public static void ChangeIt() 
      { 
       MyValue = !MyValue; 
       Task.Factory.StartNew(ChangeIt); 
      } 
    } 
} 

Заранее спасибо и счастливых праздников всем :-)

+2

Здесь вам не нужно вводить здесь нить, просто заставьте свойство вернуть обратное значение очень простое время его чтения. –

+1

Поскольку вы используете задачу для изменения значения, вызовите 'DoElseIf();' в обоих циклах, а результаты для обоих не будут одинаковыми. Проблема заключается в том, что вы используете общую переменную MyValue, доступную двумя потоками. –

ответ

3

R # является очень полезным инструментом, который поможет вам лучше писать код. Представляет ли это предложение никогда не нарушать рабочий код? Нет, это также причина, по которой кнопка «да для всех предложенных рефакторингов» отсутствует.

Чтобы ответить на ваш вопрос несколько более общий: вы всегда должны понимать, что R # меняет ваш код. Вы программист.

PS: Когда вы обнаружите сценарий, когда R # нарушает рабочий код, попробуйте еще раз взглянуть на этот фрагмент кода, он может быть и низкого качества.

PPS: Я использую R # в течение очень долгого времени уже, и никогда не бежал в пример, где R # предложил реализовать ошибку :)

+0

Понял. Я просто удивлен тем, что R # на самом деле предлагает что-то, что МОЖЕТ в конечном итоге создать код, который работает как ожидалось. – CJe

+3

Ну, честно говоря, пример, который вы предоставляете, выглядит безумным. Постоянно обновляя MyValue, а другой поток выполняет чтение на этом свойстве, кажется очень хорошим рецептом для такого рода условий гонки. Единственная причина, по которой ваш оператор switch никогда не приходит в этом состоянии, заключается в том, что для свойства есть только одна проверка, в то время как вы выполняете две проверки свойства с помощью оператора if. Это не так много, как «странное предложение» от R #, но скорее очень хороший пример программирования :) – bas

5

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

Обычно вы хотите предотвратить такие случаи, потому что это может привести к очень плохим проблемам.

И в отношении вашего вопроса, как ReSharper знает об этом факте? Обычно, если вы выполняете if/elseif, мы можем ожидать, что оператор будет правильно оцениваться правильно?

Кроме того, коммутатор даже помогает предотвратить такого рода беспорядок, поэтому, на мой взгляд, R # правильно;)

Но, конечно, вы не можете доверять R # вслепую, без двойной проверки предложения. Часто некоторые предложения являются дерьмо, и вы также должны настроить R # в соответствии с руководящими принципами кода стиля и т.д ... Это просто инструмент;)

0

После комментария Лассе, вот более короткий пример:

class Program 
{ 
    private static bool _pathological = true; 
    private static bool Pathological 
    { 
     get 
     { 
      return (_pathological = !_pathological); 
     } 
    } 

    static void Main(string[] args) 
    { 
     DoElseIf(); 
     DoSwitch(); 

     Console.WriteLine("Work's done!"); 
     Console.ReadLine(); 
    } 

    static void DoSwitch() 
    { 
     switch (Pathological) 
     { 
      case true: 
       //Console.WriteLine("true"); 
       break; 
      case false: 
       //Console.WriteLine("false"); 
       break; 
      default: 
       Console.WriteLine("WTF (Switch)!"); 
       break; 
     } 
    } 

    static void DoElseIf() 
    { 
     // R# offers Convert to Switch on the below if, which results 
     // in the code in DoSwitch, which has *different* behaviour 
     if (Pathological == true) 
     { 
      //Console.WriteLine("true"); 
     } 
     else if (Pathological == false) 
     { 
      //Console.WriteLine("false"); 
     } 
     else 
     { 
      Console.WriteLine("WTF (Else-if)!"); 
     } 
    } 
} 

Я согласен, что это ошибка в ReSharper; вы должны отправить его на адрес ReSharper bug tracker. ReSharper неправильно предполагает, что последующие значения свойства возвращают одно и то же значение. Он также неправильно предлагает преобразовать в переключатель для volatileполе, что также плохо.