Loading DLLs at runtime in C#

C#ReflectionDll

C# Problem Overview


I am trying to figure out how you could go about importing and using a .dll at runtime inside a C# application. Using Assembly.LoadFile() I have managed to get my program to load the dll (this part is definitely working as I am able to get the name of the class with ToString()), however I am unable to use the 'Output' method from inside my console application. I am compiling the .dll then moving it into my console's project. Is there an extra step between CreateInstance and then being able to use the methods?

This is the class in my DLL:

namespace DLL
{
	using System;

    public class Class1
    {
		public void Output(string s)
		{
			Console.WriteLine(s);
		}
    }
}

and here is the application I want to load the DLL

namespace ConsoleApplication1
{
	using System;
	using System.Reflection;

	class Program
	{
		static void Main(string[] args)
		{
			var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
			
			foreach(Type type in DLL.GetExportedTypes())
			{
				var c = Activator.CreateInstance(type);
				c.Output(@"Hello");
			}
			
			Console.ReadLine();
		}
	}
}

C# Solutions


Solution 1 - C#

Members must be resolvable at compile time to be called directly from C#. Otherwise you must use reflection or dynamic objects.

Reflection

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                var c = Activator.CreateInstance(type);
                type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"});
            }

            Console.ReadLine();
        }
    }
}

Dynamic (.NET 4.0)

namespace ConsoleApplication1
{
    using System;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

            foreach(Type type in DLL.GetExportedTypes())
            {
                dynamic c = Activator.CreateInstance(type);
                c.Output(@"Hello");
            }

            Console.ReadLine();
        }
    }
}

Solution 2 - C#

Right now, you're creating an instance of every type defined in the assembly. You only need to create a single instance of Class1 in order to call the method:

class Program
{
    static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");

        var theType = DLL.GetType("DLL.Class1");
        var c = Activator.CreateInstance(theType);
        var method = theType.GetMethod("Output");
        method.Invoke(c, new object[]{@"Hello"});

        Console.ReadLine();
    }
}

Solution 3 - C#

You need to create an instance of the type that expose the Output method:

static void Main(string[] args)
    {
        var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
        
        var class1Type = DLL.GetType("DLL.Class1");
       
        //Now you can use reflection or dynamic to call the method. I will show you the dynamic way
        
        dynamic c = Activator.CreateInstance(class1Type);
        c.Output(@"Hello");
        
        Console.ReadLine();
     }

Solution 4 - C#

Activator.CreateInstance() returns an object, which doesn't have an Output method.

It looks like you come from dynamic programming languages? C# is definetly not that, and what you are trying to do will be difficult.

Since you are loading a specific dll from a specific location, maybe you just want to add it as a reference to your console application?

If you absolutely want to load the assembly via Assembly.Load, you will have to go via reflection to call any members on c

Something like type.GetMethod("Output").Invoke(c, null); should do it.

Solution 5 - C#

foreach (var f in Directory.GetFiles(".", "*.dll"))
            Assembly.LoadFrom(f);

That loads all the DLLs present in your executable's folder.

In my case I was trying to use Reflection to find all subclasses of a class, even in other DLLs. This worked, but I'm not sure if it's the best way to do it.

EDIT: I timed it, and it only seems to load them the first time.

Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4; i++)
{
    stopwatch.Restart();
    foreach (var f in Directory.GetFiles(".", "*.dll"))
        Assembly.LoadFrom(f);
    stopwatch.Stop();
    Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

Output: 34 0 0 0

So one could potentially run that code before any Reflection searches just in case.

Solution 6 - C#

It's not so difficult.

You can inspect the available functions of the loaded object, and if you find the one you're looking for by name, then snoop its expected parms, if any. If it's the call you're trying to find, then call it using the MethodInfo object's Invoke method.

Another option is to simply build your external objects to an interface, and cast the loaded object to that interface. If successful, call the function natively.

This is pretty simple stuff.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondanbroooksView Question on Stackoverflow
Solution 1 - C#Dark FalconView Answer on Stackoverflow
Solution 2 - C#Reed CopseyView Answer on Stackoverflow
Solution 3 - C#AlbertoView Answer on Stackoverflow
Solution 4 - C#FredrikView Answer on Stackoverflow
Solution 5 - C#Samuel CabreraView Answer on Stackoverflow
Solution 6 - C#ChrisHView Answer on Stackoverflow