Может ли Visual Studio или другой инструмент сравнить два фрагмента кода по поведению? - PullRequest
0 голосов
/ 15 мая 2018

При программировании часто, если не всегда, есть несколько способов получить одно и то же поведение.

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

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

Вот пример:

1:

static void main()
{
    string i = "Hello World!";
    Console.Write(i);
}

2:

static void main()
{
    string helloWorldString = "Hello World!";
    Console.Write(helloWorldString);
}

3:

static void main()
{
    string myString = "Hello World!";
    WriteToConsole(myString);
}

static void WriteToConsole(string text)
{
    Console.Write(text);
}

Эти 3 примера простых программ Hello World должны вести себя одинаково, по крайней мере с точки зрения пользователя, исключительные крайние случаи конфигурации системы не включены.Я ожидал бы, что одна и та же машина будет делать одно и то же во всех трех случаях.

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

Но при некотором рефакторинге вы можете быстро понять, как "С вашими изменениями,поведение изменилось, даже если вы не заметили "или" поведение до и после того, как ваши изменения остались прежними ", будет иметь большое значение для экономии времени.

Существует ли такой инструмент в VisualStudio, Resharper или доступны где-нибудь еще?

В качестве дополнительного упражнения, потому что мне любопытно, если оно не существует для C #, существует ли оно для других языков?Существуют ли известные проекты для этого?

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Это не может быть сделано. Одной из проблем является проблема остановки, о которой @BJMyers уже упоминали в своем комментарии. Но еще одним препятствием является то, что даже ваши маленькие фрагменты на самом деле не делают то же самое. Давайте посмотрим на IL, который они производят. Сначала для № 1:

IL_0000:  nop         
IL_0001:  ldstr       "Hello World!"
IL_0006:  stloc.0     // i
IL_0007:  ldloc.0     // i
IL_0008:  call        System.Console.Write
IL_000D:  nop         
IL_000E:  ret         

и для # 2:

IL_0000:  nop         
IL_0001:  ldstr       "Hello World!"
IL_0006:  stloc.0     // helloWorldString
IL_0007:  ldloc.0     // helloWorldString
IL_0008:  call        System.Console.Write
IL_000D:  nop         
IL_000E:  ret         

Ну, они идентичны - что неудивительно, поскольку единственное отличие - это имя переменной, которой больше нет в скомпилированном коде. Но теперь для № 3:

IL_0000:  nop         
IL_0001:  ldstr       "Hello World!"
IL_0006:  stloc.0     // myString
IL_0007:  ldloc.0     // myString
IL_0008:  call        UserQuery.WriteToConsole
IL_000D:  nop         
IL_000E:  ret         

WriteToConsole:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  call        System.Console.Write
IL_0007:  nop         
IL_0008:  ret   

Как вы можете видеть, он имеет еще 3 инструкции (не считая nop здесь). Таким образом, вашему инструменту нужно будет проверить IL и определить, какой результат дает какой вклад. И это вернет нас к проблеме остановки. Конечно, статический анализатор может идентифицировать некоторые шаблоны, но общее решение невозможно.

Если ваша цель - убедиться, что рефакторинги ничего не сломали, лучшее, что вы можете сделать, - это модульные тесты, как @dktaylor уже предлагал в своем ответе.

0 голосов
/ 16 мая 2018

Как правило, вы не можете статически анализировать поведение кода, поскольку оно может зависеть от среды, такой как файлы и пользовательский ввод.

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

void Program.Main([])
   void Program.WriteToConsole("Hello World!")
     void Console.Write("Hello World!")
      >SyncTextWriter Console.get_Out()
       void SyncTextWriter.Write("Hello World!")
         void StreamWriter.Write("Hello World!")
           void StreamWriter.CheckAsyncTaskInProgress()
          >void String.CopyTo(0, [�, �, �, �, �, �, �, �, �, ...246..., �], 0, 12)
           void StreamWriter.Flush(true, false)
            >12 EncoderNLS.GetBytes([H, e, l, l, o,  , W, o, r, ...246..., �], 0, 12, [0, 0, 0, 0, 0, 0, 0, 0, 0, ...247..., 0], 0, false)
            >void __ConsoleStream.Write([72, 101, 108, 108, 111, 32, 87, 111, 114, ...247..., 0], 0, 12)
            >void __ConsoleStream.Flush()

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

Кстати, использование автоматизированных инструментов для проведения рефакторинга, безусловно, сохраняет поведение программы.

0 голосов
/ 15 мая 2018

Я считаю, что вы ищете модульное тестирование. Они позволяют вам тестировать результат какой-либо функции, не беспокоясь о реализации. Посмотрите здесь:

Начало работы

...