Sunday, January 06, 2008

Referencing different versions of an assembly - Part 3 (ILMerge)

(if you missed the first and the second parts...)

We have succeed build our solution using ILMerge with the flag /internalize.

But now lets go a step further:

image

A.dll + infra V1 => MergedA.dll (using /internalize)
B.dll + infra V2 => MergedB.dll (using /internalize)

App1 + MergedA.dll + MergedB.dll => MergedApp1.dll

 

Will it work?

At first look, the answer should be it won't.

Why? remember that the reason it worked before was because infra1 & infra2 were declared Internal.

But now they both on the same Assembly (MergedApp1) so we should get an error from ILMerge about the same type declared more than once...

 

But if you try it, you'll find out it works...

How?

A another look with reflector will reveal the secret:

image

What happened? Where come from those MergedA850 and MergerdB1071 ?

The magic sits inside ILMerge. it has noticed the conflict between the two types with the same name (which now inside the same assembly - so "Internal"won't help) and just made each of them a new name!

read the following section from ILMerge help file:

The normal behavior of ILMerge is to not allow there to be more than one public type with the same name. If such a duplicate is found, then an exception is thrown. However, ILMerge can just rename the type so that it no longer causes a conflict. For private types, this is not a problem since no outside client can see it anyway, so ILMerge just does the renaming by default.

So, because Infra1 & Infra2 weren't public - they just got new names.

(Actually, you can do it for public types as well - using the /allowDup flag).

 

Is it a good solution?

 

In my opinion (or better phrased: with my situation) it isn't.

  1. Renamed types can break your application:

    If you use reflection in your code you may plan getting a type by its name.
    But now it has a different name...
  2. Multiple copies of the same type is loaded into memory:

    guess what happens if you have a singleton class in the Infra.dll.
    You can end up with 3 instance of one singleton... (ouch).

 

So back to square one -
How to reference multiple versions of the same assembly?

We have left with the two original options:

  1. Put the two DLLs into different folders, and tell the application to probe those folders.
  2. Install the DLLs into the GAC.
    This way they won't be copied into the Bin at all.
  3. Add the DLL's version to their name (e.g. Infra-1.dll)

Which one? Let's continue next time.