tags:

views:

317

answers:

2

What's the best practice for bundling one assembly in another? I have an assembly I'm distributing, but I have a couple third-party assemblies that I use in it, and I don't want to have to distribute more than one.

So, I'd like to compile a couple assemblies into the one I distribute so that they're just built-in.

What's the best practice for this? I know I can put the other assemblies in my project and set them to "embedded resource," but how do you get them back out again, meaning how do you get it to a place where I can instantiate classes defined in that embedded assembly?

I've seen the Assembly.Load method, but it seems to want a file path. Is there another way to load embedded assemblies? How do you tell the Load method where the assembly is?

Once you load the embedded assembly, is it just magically in scope and can I freely instantiate classes from it?

+5  A: 

There's an Assembly.Load(byte[]) overload that you can use to load assemblies from an in memory array. If I remember correctly, that's the way LINQPad works for instance. Here's a way to do it, given assembly being an instance of System.Reflection.Assembly, containing other assemblies as managed resources:

Stream embedded = assembly.GetManifestResourceStream ("asm.dll");
byte [] buffer = new byte [embedded.Length];
using (embedded) {
    int length = buffer.Length;
    int offset = 0;
    while (length > 0) {
     int read = assemblyStream.Read (buffer, offset, length);
     if (read == 0)
      break;

     length -= read;
     offset += read;
    }
}

Assembly assembly = Assembly.Load (buffer);

The issue with this one is that the runtime have to pin the byte array, so I'd suggest writing the assembly to a temporary file and use Assembly.LoadFile.

Both methods return a System.Reflection.Assembly object, that you can use to get types and then do whatever you want with them.

Jb Evain
What's the step beyond this, when you actually get classes? Once you load the assembly, and have an Assembly object, are all the classes defined in it now in the global scope?
Deane
The Assembly is loaded in the current AppDomain. You can then use Assembly.GetType () to get types, and use Activator.CreateInstance to instantiate them. As the assembly is loaded dynamically, you have to instantiate type dynamically.
Jb Evain
+4  A: 

I would recommend the ILMerge utility, which combines all the assemblies into a single one by fixing up the references instead of loading the original assemblies from resources.

jachymko