Dinamik Olarak Dll Yükleme ve Kullanma

.NET ile yazılmış bir dll’i projeye eklemeden, dosya yolunu göstererek kullanabiliriz. Aşağıdaki örnek için çağırılacak sınıf ve metot statik olmalıdır.

using System;
using System.IO;
using System.Reflection;

namespace DynamicLoadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = CallMethod(@"C:\SampleDll.dll", "Add", new object[] { 5, 4 });

            if (result is Exception)
            {
                Console.WriteLine("Some errors occured!");

                Console.ReadKey();
            }

            Console.WriteLine(result);

            Console.ReadKey();
        }

        private static object CallMethod(string assemblyFile, string methodName, object[] parameters)
        {
            try
            {
                var a = Assembly.LoadFrom(assemblyFile);

                var mi = a.GetTypes()[0].GetMethod(methodName);

                return mi.Invoke(null, parameters);
            }
            catch (Exception ex)
            {
                return ex;
            }
        }
    }
}

Yukarıdaki yöntem çok esnek bir yöntem değil. Methot adlarını bilmek gerekiyor. Bunun yerine .NET kütüphanesinde bulunan MEF(Managed Extensibility Framework) kütüphanesini kullanabiliriz. Bu kütüphane System.Composition altında bulunmaktadır.

Bir interface oluşturulur.

namespace CompositionTest
{
    public interface IOperation
    {
        int Add(int a, int b);

        int Subtract(int a, int b);

        double Divide(int a, int b);

        int Multiply(int a, int b);
    }
}

Interface’de kullanmak için modül tipi metadata’sı oluşturulur.

namespace CompositionTest
{
    public interface IOperationMetadata
    {
        ModuleTypes ModuleType { get; }
    }
}

MEF kütüphanesini kullanmak için yardımcı bir sınıf oluşturulur.

using DynamicLoadTest;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Reflection;

namespace CompositionTest
{
    public class MefHelper
    {
        [ImportMany]
        public IEnumerable<Lazy<IOperation, IOperationMetadata>> operations;

        public void Setup()
        {
            try
            {
                operations = new List<Lazy<IOperation, IOperationMetadata>>();

                var aggregate = new AggregateCatalog();
                //aggregate.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
                aggregate.Catalogs.Add(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).Location)));

                var parts = new CompositionBatch();
                parts.AddPart(this);

                var container = new CompositionContainer(aggregate);
                container.Compose(parts);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }
    }
}

Modül tipleri enum’u oluşturulur.

namespace CompositionTest
{
    public enum ModuleTypes
    {
        None, AnotherModule, SampleModule
    }
}

Aşağıdaki gibi kullanabiliriz.

using CompositionTest;
using System;
using System.Linq;

namespace DynamicLoadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var mh = new MefHelper();

            mh.Setup();

            Console.WriteLine(mh.operations.First(f => f.Metadata.ModuleType == ModuleTypes.AnotherModule).Value.Add(10, 4));

            Console.WriteLine(mh.operations.First(f => f.Metadata.ModuleType == ModuleTypes.SampleModule).Value.Add(10, 4));

            Console.ReadKey();

            Console.WriteLine(mh.operations.First(f => f.Metadata.ModuleType == ModuleTypes.AnotherModule).Value.Add(10, 4));

            Console.WriteLine(mh.operations.First(f => f.Metadata.ModuleType == ModuleTypes.SampleModule).Value.Add(10, 4));

            Console.ReadKey();
        }
    }
}

Örnek dll sınıfı.

using CompositionTest;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AnotherModule
{
    [Export(typeof(IOperation))]
    [ExportMetadata("ModuleType", ModuleTypes.AnotherModule)]
    public class Operation : IOperation
    {
        public int Add(int a, int b)
        {
            return -1;
        }

        public int Subtract(int a, int b)
        {
            return -2;
        }

        public double Divide(int a, int b)
        {
            return -3;
        }

        public int Multiply(int a, int b)
        {
            return -4;
        }
    }
}

Örnek projeyi buradan indirebilirsiniz.