有没有一个适用于C#的高级差异比较工具?

17

我正在寻找一种可以分析我的代码并告诉我哪些构造发生了变化的差异工具。

例如,如果我将一个方法从文件开头剪切并粘贴到末尾,但保持该方法不变,则不希望被标记。但是,如果我在该方法中插入一行代码或更改某些内容,则会被标记为已更改。

我使用过各种差异工具,但它们似乎都无法以任何逻辑方式告诉您哪些行已被插入、删除或更改。如果我定期重新排列代码文件的布局,那么差异工具能够跟上就好了。

有人有这样的工具吗?


1
这不是源代码控制变更注释的作用吗? :) - jrummell
你还在等待支持团队的回复吗?我很想知道你找到了什么。 - Robert Greiner
仍在等待。他们联系我询问我需要哪个版本的C#方言。我告诉他们我需要2.0 (.NET 3.5)版本,并询问价格以及是否会发布试用版,但自那以后就没有收到他们的回复了。 - BenAlabaster
@Ben:我在2009年9月4日给你发了一封邮件,邀请你参与C# 3.0的beta版本测试。但是没有得到回复。 - Ira Baxter
Ben已经要求并收到了一份beta副本。 - Ira Baxter
大家都不知道Ben去哪儿了。生产版本早已发布,您可以从网站上下载一个评估版。 - Ira Baxter
12个回答

22

我使用 http://winmerge.org/

我认为你无法做到你所要求的,因为这些工具的最长公共子序列算法的工作方式。

即使您的函数被重新排列,您的源文件的功能仍然保持不变,由于LCS的性质,它仍将显示为差异。

编辑:
这有点牵强,但如果你感觉特别有雄心壮志,你可以编写适合你自己需求的代码。

你可以使用正则表达式从源文件中提取每个方法,并根据其名称单独对每个方法进行LCS diff。 您可以将您的代码存储在一个字典(键,值)中,以便键是方法的名称,而值是函数的字符串。 然后,您只需将dictionary_orig ['method']与dictionary_new ['method']进行差异比较即可。

除此之外,我不知道如何实现您所寻找的内容。


1
实际上,Winmerge有一个选项可以检测移动的文本块。它们将与更改或添加/删除的文本块标记不同。 - VladV
我仍然认为“标记”是一个合适的术语。 - Robert Greiner
Ira Baxter发布了一篇可能正是程序员需要的差异对比工具的文章,它潜在地支持许多语言。我正在等待他们支持团队的回应,以确定它是否真正实现了所有承诺。 - BenAlabaster
正则表达式?真的吗? - jeroenh

9

请查看我们的Smart Differencer工具,它比较抽象语法树,并以AST所代表的非终结符(“语言构造”)和可能的编辑操作(插入、删除、移动)报告差异,以及发现一致的重命名。

目前,它仅处理Java和COBOL,但它基于DMS,该软件具有广泛的语言解析器,包括C#。

编辑9/8/2009:现在可供beta测试人员使用C# SmartDifferencer。

该工具已将整个文件中的一致重命名视为语义上微不足道的(假设其他文件相应引用了重命名的符号),以及作用域内的重命名。我们计划考虑语义上微不足道的变化,例如在Java和C#类中移动方法声明。

编辑2010年10月:生产版本已经发布。您可以在网站上访问评估下载。

编辑2012年5月:您可以在此页面上查看C#示例。

目前它没有忽略语义上的空编辑。一个特殊的例子是在类主体中移动方法;我们都知道这对于C#的语义没有影响。我们的工具比较语法(通过AST),而不是语义,因此它不理解这个特定的细微差别,将会告诉用户“已经被移动”,而不是保持沉默。我们计划在未来处理这类情况,但嘿,每个产品都必须有一个版本1 :-} [作为微妙的一点,Java类中的方法调换也是语义上空的,但交换字段由于初始值计算顺序不同而不是这样。我不知道这是否也适用于C#,但这并不让人吃惊。]


1
Richard的链接问题在于他的链接被错误地转录了。您可以访问http://www.semanticdesigns.com/Products/SmartDifferencer/CSharpSmartDifferencer.html并从那里轻松下载评估版。 - Ira Baxter
@John:链接的网页指向一个示例页面,标签为“here”的链接相对较短(也许我们应该改变这个)。公平地说,它并不完全符合OP的要求,但它非常接近。它会告诉他他移动了代码块,并且块内容没有改变,或者如果确实有改变,会给出一个“最小”的编辑来解释这种改变。 - Ira Baxter
@IraBaxter:这非常接近,而且由于您的产品是我听说过的唯一一个接近实现此功能的产品,我建议您展示它。如果您的产品不能满足OP的所有要求,则提及它不能做什么以及为什么不能做什么将是很好的。 - John Saunders
@John:糟糕,索引页面引用了一个通用页面,该页面指向C#页面(以及其他语言的页面,每个页面都有一个特定于语言的示例链接)。我在答案中放置了一个明确的C#示例链接和一些讨论。 - Ira Baxter
1
大家好,只想添加一段视频剪辑,讨论SemanticDesigns的SmartDifferencer,由该公司首席执行官在GoogleTechTalks上发表演讲。链接为 https://youtu.be/C-_dw9iEzhA?t=2361。 - jxramos
显示剩余4条评论

6

你愿意比较编译后的程序集吗?如果愿意,.NET Reflector有一个叫做Diff的插件可以让你比较两个程序集。这样做肯定不会关心你的对象在源文件中如何排列。


这是一个有趣的想法 - 理论上我不需要对不进入版本控制系统的文件进行差异比较,只有可编译的应用程序才会放在那里,所以这可能有效 - 正如我所说,理论上。我会去检查一下这个途径。 - BenAlabaster
这不是一个“完美”的解决方案,但它提供了一种有趣的方法来看看编译器另一侧的区别。如果您还没有使用过.NET Reflector,请确保查看其他插件,因为它们肯定会使已经令人印象深刻的工具变得更好。对于那些对此回答进行了负面评价的人,请解释原因。如果您发现我的回答有缺陷,您应该站出来说出您发现的问题。 - Chris Porter

3

2
我认为SemanticMerge非常有帮助。它以良好的视觉方式显示差异,并且轻松比较复杂的C#代码。

作为 SemanticMerge 的长期用户,我想向任何未来的观众指出,这个产品不幸地不再作为独立产品提供,而必须作为其 SCM 套件的一部分购买。 - mellamokb

2

这也是我一直在思考的问题。我认为目前还没有这样的工具。对于其他情况,有“功能性”(而不仅仅是基于文本)的差异工具可用。例如,Microsoft Word集成了自己的差异/合并功能(可以脚本化,因此可以与TortoiseSVN等集成),还有几个可用于XML的工具,它们解释xml文件而不仅仅将其视为文本。

我不确定这样的工具相比良好的基于文本的差异/合并工具的附加值是否足以证明开发它。另一方面,这可能只是解决我们在处理困难的合并情况时所感受到的“合并痛苦”的缺失环节。

当然,难点在于您必须以与C#编译器相同的方式解释代码。目前来看,最接近的工具确实是NDepend。我认为这篇博客文章解释了它在这方面的一些能力。


2

对于这个问题,Scooter Software 的Beyond Compare非常好用,而且价格便宜(30美元)。


也有人建议Jeff在编写StackOverflow时使用了这个。http://highscalability.com/stack-overflow-architecture - John MacIntyre

1

我知道你正在寻找一种工具。但是既然我不知道有什么工具可用,那么这就是我如何完成它的方法:

  1. 阅读一本编译器设计的书籍
  2. 对你的代码进行词法分析和语法分析
  3. 创建一个抽象语法树
  4. 发明一种在语法树上执行差异操作的算法
  5. 获得收益!

已经在考虑这个问题了 - 我认为这将是一个很棒的工具,因为显然还没有类似的工具存在。唯一的问题是,如果一个类有依赖关系,而这些依赖关系不能仅通过文件本身满足,那么如何进行词法分析/解析呢?这是行不通的... - BenAlabaster
也许这将是一个完整的“项目”或“解决方案”的不同之处。您的编译器已经处理了这个问题,所以应该不难弄清楚。如果可能的话,使它与语言无关也很好。这样其他语言就可以轻松添加进来。我相信很多人会愿意把它作为产品购买。 - Carlos Rendon

0

我使用KDiff,发现它运行得非常好。而且当然是免费的。


1
我正在寻找一款能够分析我的代码并告诉我每个构造体发生了哪些变化的差异工具。DiffMerge能够实现这个功能吗?-1 - John Saunders

0

正如许多人所建议的那样,我猜测这种比较可能无法使用现有的差异工具进行。因为它们的目的是判断是否有变化,如果您将一个方法从开头移到结尾,实际上确实发生了变化。

但是我现在想到的是,您可以自己完成它。基本上调用一些差异工具,然后返回新插入的行,基本上是您已将其移动到文件末尾的方法。然后您可以自己进行比较,看看更改的行是否已经存在于以前的文件中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接