Error 2 The type exists in both… with ILMerge

2019-08-07 17:25发布

问题:

I have 3 projects:

  • A_MainProject (startup project)
  • B_IntermediateProject
  • C_SharedClassLibrary

The depencies are:

A depends on B & C

B depends on C

and C depends on System only.

Every Project has it's own namespace.

As long as no ILMerge is installed, everything works fine.

If ILMerge is activated for Project A ("A_MainProject") everything still works fine and one self-contained executable for Project A is generated.

If ILMerge is now also activated for the B_IntermediateProject, I get the following error:

Error   2   The type 'C_SharedClassLibrary.SharedClass' exists in both 'c:\dev\ILMergeError\B_IntermediateProject\bin\Debug\B_IntermediateProject.exe' and 'c:\dev\ILMergeError\C_SharedClassLibrary\bin\Debug\C_SharedClassLibrary.dll'    C:\dev\ILMergeError\A_MainProject\Program.cs    12  A_MainProject

I use "MSBuild ILMerge task" 1.0.3-rc2 with "ILMerge" 2.13.0307 (from mbarnett).

The minimal solution contains 3 Projects with one class each. This version has ILMerge activated on only one project and works:

ILMergeError_stillworking.zip

This version has it also activated on project B and produces the error:

ILMergeError_error.zip

If I merge the two exes and the dll with ILMerge externally (ILMergeGUI) everything works fine.

Thank you in advance for answering, Xan-Kun

回答1:

The short answer is that you should only enable ILMerge on A, where it'll merge both A+B+C together.

The reason why you hit this error is that when you enable ILMerge on B, B will be repacked with all C types as well (B' = B+C). Hence when ILMerge triggers on A, it'll merge A+B'+C = A+(B+C)+C

Now 2 scenarios can happen:

  1. B uses C internally, and doesn't (publicly) expose any C type (e.g. as method argument or return value). In this case you can make it work through ILMerge options (/internalize on B and /allowDup on A), though you'll end up with twice every C type in the merged assembly A.

  2. B exposes C types, that are maybe used by A. In this case even if you manage to make the merge work, it'll fail at runtime, because A and B' reference different types (e.g. for a class c, B' references B'.c and A references C.c), And you'll get nasty type cast exceptions, because those are 2 different types (same name, same namespace, but different assemblies).

(They're nasty because they don't indicate the assembly mismatch, and exception only says that "c cannot be cast to c", which can be confusing to many)