Dynamic DLL loading with reflection


We often have to load different class libraries runtime. The code segment below solves this problem efficiently. Only you have to call the InvokeDllMethod of the DllLoader class with these parameters: first is the absolute path of the DLL you want to load, second is the name of the method you want to call and the third is the input parameters in an object array for the method of the DLL.

In the GetClassReference method we are searching for the method's class as a class which implements the IComparable interface. So in this case we suppose that the class which implements the IComparable interface has the method that we passed as the second parameter of InvokeDllMethod. Here you can search the class in different ways (e.g. name of class).

This solution is very efficient because we don't load the assembly or the class again if we loaded it before. We use two hashtables (one for classes, one for assemblies) to store references. Hashtables are efficient data structures because we can insert elements and search in the hashtable in constant time, so it is very fast. If we load same assemblies in every method calling, our program will be so redundant...
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SampleApp
{
    public static class DllLoader
    {
        private class DllLoaderClassInfo
        {
            public Type type;
            public object ClassObject;
 
            public DllLoaderClassInfo() { }
 
            public DllLoaderClassInfo(Type t, object c)
            {
                type = t;
                ClassObject = c;
            }
        }
 
        private static Hashtable AssemblyReferences = new Hashtable();
        private static Hashtable ClassReferences = new Hashtable();
 
        private static DllLoaderClassInfo GetClassReference(string AssemblyName)
        {
            if (ClassReferences.ContainsKey(AssemblyName) == false)
            {
                Assembly assembly;
                if (AssemblyReferences.ContainsKey(AssemblyName) == false)
                {
                    AssemblyReferences.Add(AssemblyName, assembly = Assembly.LoadFrom(AssemblyName));
                }
                else
                {
                    assembly = (Assembly)AssemblyReferences[AssemblyName];
                }
                foreach (Type type in assembly.GetTypes())
                {
                    bool implementsIComparable = typeof(IComparable).IsAssignableFrom(type);
                    if (implementsIComparable)
                    {
                        DllLoaderClassInfo ci = new DllLoaderClassInfo(type, Activator.CreateInstance(type));
                        ClassReferences.Add(AssemblyName, ci);
                        return (ci);
                    }
                }
                throw (new Exception("Could not instantiate class!"));
            }
            return ((DllLoaderClassInfo)ClassReferences[AssemblyName]);
        }
 
        public static object InvokeDllMethod(string assemblyName, string methodName, object[] args)
        {
            DllLoaderClassInfo ci = GetClassReference(assemblyName);
            object Result = ci.type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, ci.ClassObject, args);
            return (Result);
        }
    }
 
    private class Program
    {
        private static void Main(string[] args)
        {
            object[] inputParams = new object[] { "abc", 1, DateTime.Now };
            DllLoader.InvokeDllMethod(@"D:\ClassLibraries\SampleClassLib.dll", "SampleMethod", inputParams);
        }
    }
}

Posted on 13:43 by csharper and filed under , , , , | 0 Comments »

0 comments:

Post a Comment