如何识别重复的程序集?
虽然我正在查看关于MEF的一些问题,但我偶然发现了this particular answer的问题。这让我想起了这么一点,因为我从来没有尝试过这样做,但在这个问题的场景中可以看到它非常有效。如何识别重复的程序集?
场景: 如果你有不同的.NET程序集的目录中的所有命名不同,你会怎么能够识别那些可以是相同的,但改名(即复制MyAssembly.dll程序VS MyAssembly.dll程序) ?
我能想到以下项目:
检查文件大小(应该是相同的)
检查程序集版本号
循环通过该组件使用反射和尝试找出差异。
是否有解决此问题的任何其他/更简单的方法?是否有其他标准来查看确定2个不同名称的DLL实际上是否是相同的编译程序集?
起初我以为你可以用Equals
或ReferenceEquals
来做到这一点,但这个证明太容易出错。例如,如果您使用Assembly.LoadFile
,则这不起作用。
随着nUnit,我做了下面的测试,这些测试有点基本,但给你一些继续。加载类型的方式很奇怪(请参阅MSDN)。我假设你知道如何做“快速测试”,以防你想检查二进制等,等等(见下面的PS)。
Assembly asm1 = Assembly.LoadFile(@"someDebugAssembly.dll");
Assembly asm2 = Assembly.LoadFile(@"someReleaseAssembly.dll");
// load all the types (the double try/catch is on purpose)
Type[] types1 = null
Type[] types2 = null;
try
{
types1 = asm1.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
types1 = e.Types;
}
try
{
types2 = asm1.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
types2 = e.Types;
}
// same length
Assert.AreEqual(types1.Length, types2.Length);
// check each type
IEnumerator types1Enumerator = types1.GetEnumerator();
types1Enumerator.Reset();
foreach (Type t in types2)
{
types1Enumerator.MoveNext();
Assert.AreEqual(types1Enumerator.Current, t);
}
关于代码的说明:这种比较方法将两个包含相同类型的程序集视为相等。这意味着调试和发布版本,或不同的版本,都没有考虑在内。使用asm1.GetName()
及其属性(再次:不要使用Equals!)来比较各个字符串(版本,全名等)。 PS:定义什么构成两个相等的组件是有趣的,:
- 它们是二进制等于
- 有版本,完全合格的名称是相等的
- 强名称相同
- 所有类型,深受相比,具有相同的签名
视你选择什么,两个完全不同的程序集(即调试版本与发布版本)可以相同。这真的取决于你想如何比较。
更新:纠正以前的错误,并添加代码示例
取决于你如何加载它们http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx – erikkallen 2009-11-16 18:15:45
@erik:对,我在测试时得出了相同的结论。我在编辑答案。 – Abel 2009-11-16 18:24:03
我会先使用第1点和第2点进行简单的快速检查,即检查文件大小和程序集版本号。如果它们完全不同,那就完成了。
如果不是,请保留具有相同文件大小/版本的文件并计算它们的MD5/SHA1 /无论你喜欢的散列。如果哈希值相同,那么您肯定在同一个程序集中存在两次。由于程序集通常不是很大(最多几兆字节),哈希计算应该足够快。
不,两个组件可能会以相同的散列(鸽子层原理)结束。要完全确定,你必须逐字节比较它们。 – erikkallen 2009-11-16 18:14:47
你也可以使用好老
补偿命令行程序:
c:\tests> comp one.dll two.dll Comparing one.dll and two.dll... Files compare OK
更新:更好。下载Windows XP Service Pack 2 support tools,安装它(选择完成安装)。然后进入“运行命令”对话框并输入dupfinder。将它指向您想要的文件夹,您将开始在该路径及其子文件夹中记录所有重复项。
确实在寻找一个.net /程序化的答案,但我没有指定这样的东西,那是我的错。绝对好知道,因为我不知道重复。谢谢 – JamesEggers 2009-11-16 18:23:25
然后我会先比较大小,然后使用类似Mono.Cecil的东西来检查程序集名称/版本/签名(如果签名),而不实际加载程序集。然后,如果程序集没有签名,只需逐字节比较... – Gonzalo 2009-11-16 18:38:19
@james,你说你真的在寻找一个程序化的解决方案。检查代码,这是否会更接近?让我们知道我们可以改进的地方。 – Abel 2009-11-17 19:57:10
@Abel我希望今晚能测试一下。我无法像我希望昨晚那样,希望今晚我能知道更多。今晚会让你知道/标记一个答案。 – JamesEggers 2009-11-17 20:24:41