Using reflection on files already loaded in an app domain instead of loading every file (again)

StackOverflow https://stackoverflow.com/questions/20476352

  •  30-08-2022
  •  | 
  •  

Question

I'm using reflection to scan all of the assemblies in a folder for types that implement a certain interface and derive from a certain base class. The code looks like this:

foreach (string file in Directory.GetFiles(folder, "*.dll"))
{
    Assembly assembly = Assembly.LoadFile(file);

    Type foundType = (from type in assembly.GetTypes()
                      where type.GetInterfaces().Contains(typeof(TInterface))
                   && type.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
                      select type).FirstOrDefault();

    if (foundType == default(Type)) { continue; }

    // Register our type so we don't need to use reflection on subsequent requests.
    DependencyContainer.Register(typeof(TInterface), foundType);

    return CreateInstance<TInterface>(foundType);
}

During a code review, two concerns were brought up concerning this piece of code. First, we can't shortcut the loop once we find a matching type; we need to loop through every file and throw an exception if we find more than one matching type. That brings me to the real issue here...

The code reviewer wondered if there was a better way to load every file. For performance reasons, we're wondering if we can loop through files already loaded in the app domain, instead of calling Assembly.LoadFile(file) for every file. We thought, why load every file if it's already loaded? Is this a valid concern? Is loading a file this way the same as how files get loaded into an app domain? What would be an efficient way to loop through every file so we're not wasting processing time?

Note: The documentation for Assembly.LoadFile() isn't quite helpful:

Loads the contents of an assembly file on the specified path.

I'm not sure if that equates to how files are loaded into an app domain, or if that's a different scenario altogether.

Was it helpful?

Solution

If you use LoadFrom instead of LoadFile, you don't have to worry about that - if the DLL is already loaded, it will not be loaded again - see http://msdn.microsoft.com/en-us/library/1009fa28.aspx. However, note that this is based on the assembly identity, not path, so if you're concerned that there could be two assemblies, each with the same identity but a different path, you're stuck with loading them explicitly each time.

If you really want to dig deeper into this, you can get all the assemblies loaded in your application domain using AppDomain.CurrentDomain.GetAssemblies, building a dictionary or some such structure and skipping those already loaded. However, as I said, in a typical scenario and using LoadFrom, it's unnecessary.

OTHER TIPS

I don't know exactly how Assembly.LoadFile(file) behaves. But you can always check each individual assembly against the already loaded ones via AppDomain.CurrentDomain.GetAssemblies().

Another approach is to add the folder to the private probing path and then use Assembly.Load(string) which loads the assemblies in the Load context. This is the recommended way as far as I know. Check the MSDN blog of Suzanne Cook for more info and advice on assembly loading.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top