43

Here's my problem:

I have 2 projects - one 'common' projects with acts like a library with all kinds of support code, and the actual program that uses said project in many of its calls. We'll call these projects "Common" and "Program". They are both in the same solution.

Within "Common", I have a class for common reflection tasks, like creating an instance. If I call GetExecutingAssembly, it gets all the "Common" Types, however when I use GetEntryAssembly I get the "Program" types.

While I certainly could edit the code to work with 2 sets of asm, I'm afraid of a situation where there are more than just 2 projects in the solution - lets say 5 (don't know why, but lets just go there for now), and I'm afraid that calling GetExecutingAssembly and GetEntryAssembly will not get all the Types in the entire program.

Is there something else that i can do to get all the Types in a solution?

cyberconte
  • 2,371
  • 4
  • 21
  • 27

4 Answers4

92
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

This will get all of the loaded assemblies in the current AppDomain.

As noted in the comments, it's possible to spawn multiple AppDomains, in which case each can have its own assemblies. The immediate advantage to doing so is that you can unload Assemblies by unloading the containing AppDomain.

bsneeze
  • 4,369
  • 25
  • 20
  • 7
    May or may not work subject to 1) if the app spawns multiple AppDomains 2) if all ref assemblies have been loaded before this point – Gishu May 12 '09 at 05:42
  • @Gishu: "if all ref assemblies have been loaded before this point" Not quite sure what you mean by that. Can you elaborate? – bsneeze May 12 '09 at 05:46
  • 22
    Correct me if I'm wrong: The CLR won't load a referenced assemblies (even modules within a single assembly) until it is needed. E.g. So RefAsmA would be loaded only when the code in the entry assembly makes a reference to a type defined in RefAsmA - calls a static method or creates a type defined in it. At that point the assembly is loaded into the loader heap of the current AppDomain. – Gishu May 12 '09 at 05:49
49

This is a really old question, but for future reference here's a complete implementation:

    public static IEnumerable<Assembly> GetAssemblies()
    {
        var list = new List<string>();
        var stack = new Stack<Assembly>();

        stack.Push(Assembly.GetEntryAssembly());

        do
        {
            var asm = stack.Pop();

            yield return asm;

            foreach (var reference in asm.GetReferencedAssemblies())
                if (!list.Contains(reference.FullName))
                {
                    stack.Push(Assembly.Load(reference));
                    list.Add(reference.FullName);
                }

        }
        while (stack.Count > 0);

    }
3Dave
  • 28,657
  • 18
  • 88
  • 151
  • 2
    Try using hashset insteas of a list. – AgentFire Jan 22 '13 at 12:47
  • 8
    @AgentFire what's the line about premature optimization? If you have enough assemblies in your solution, or are calling this often enough, for it to make a difference, something else is wrong. In this case hash generation could very well consume more time than lookup. – 3Dave Sep 12 '13 at 22:56
  • @DavidLively Hash generation is not that consumable of cpu – AgentFire Sep 13 '13 at 04:14
  • 4
    @AgentFire yeah, but it takes more than adding an item to a linked list. For this application you'll never see a difference. – 3Dave Sep 13 '13 at 05:11
  • 1
    @3Dave Please correct me if I'm wrong, but would it be better to *also* loop through the assemblies loaded into the app-domain, in case some assemblies had been loaded dynamically (through `Assembly.Load` and similar)? – RB. May 22 '19 at 13:21
  • 1
    @RB Sure, that makes sense. :) – 3Dave May 23 '19 at 15:23
  • Assembly.GetEntryAssembly() could be null (for example in case of debugging) – LbISS May 30 '20 at 13:45
  • @LbISS It's been a few (8) years since I've thought about this. Feel free to edit the post. :) – 3Dave May 30 '20 at 22:38
14

How about GetReferencedAssemblies to work off the AssemblyRef metadata entries? The 'solution' is not something that the CLR knows or cares about. It deals in Assemblies.

private static List<Assembly> GetListOfEntryAssemblyWithReferences()
{
  List<Assembly> listOfAssemblies = new List<Assembly>();
  var mainAsm = Assembly.GetEntryAssembly();
  listOfAssemblies.Add(mainAsm);

  foreach (var refAsmName in mainAsm.GetReferencedAssemblies())
  {
    listOfAssemblies.Add(Assembly.Load(refAsmName));
  }
  return listOfAssemblies;
}

Caveats:

  1. You still need to filter core assemblies System.*
  2. This just goes one level deep in the ref chain, but can be done recursively - with more code.
Pang
  • 9,564
  • 146
  • 81
  • 122
Gishu
  • 134,492
  • 47
  • 225
  • 308
11

Also: Some assemblies are not loaded straight away, so you should also put an Event Handler on the AppDomain's assembly load event.

AppDomain.CurrentDomain.AssemblyLoad += ....
Tim Jarvis
  • 18,465
  • 9
  • 55
  • 92