Visual Studio或其他工具可以按行为比较两段代码吗?

时间:2018-05-15 18:15:52

标签: c# visual-studio resharper

编程时,通常会有多种方法来获得完全相同的行为。

我知道很多工具允许逐行比较代码文件。我正在寻找的是一种工具,可以在比较行为时提供帮助或完成整个工作。

我很清楚,在大多数情况下,在执行过程中的某些时候,副作用,内存状态,堆栈跟踪和许多其他事情会有所不同。我真的在寻找一种不会考虑所有这些因素的顶级比较。就像文字比较工具一样,可以轻松忽略空行和注释。

以下是一个例子:

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);
}

简单Hello World程序的3个示例应该表现相同,至少从用户的角度来看,不包括极端系统配置边缘情况。我希望同样的机器在所有三种情况下完全相同。

当然,至少从我的观点来看,对于计算机而言,这似乎是一项非常困难的任务。我不希望这样的工具是完美的,特别是当项目有多个类,表单,全局变量等时。

但是在进行一些重构时,快速抬头就像“随着你的改变,即使你没有注意到,行为也发生了变化”或“改变之前和之后的行为保持不变”将会有很长的路要走当谈到节省时间。

Visual Studio,Resharper中是否有这样的工具,或者在其他地方可用?

作为额外的练习,因为我很好奇,如果C#不存在,是否存在其他语言?是否有正在进行的已知项目?

3 个答案:

答案 0 :(得分:2)

这不可能。一个问题是@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在答案中已经建议的那样。

答案 1 :(得分:2)

通常,您无法静态分析代码行为,因为它可能取决于文件和用户输入等环境。

您可以使用我的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()

但是如果您的程序生成图形输出或进行数据库更改,则需要其他工具。

BTW,使用自动化工具执行重构肯定会保留程序行为。

答案 2 :(得分:0)

我相信你所寻找的是单元测试。它们允许您测试某些功能的结果,而无需担心实现。看看这里:

Getting Started