【问题标题】:Dynamically load dlls动态加载dll
【发布时间】:2015-09-23 08:01:31
【问题描述】:

我有以下主要方法。 LocalCabelTV 和 LocalDishTV 类位于主应用程序中。该程序运行良好。

我想将 LocalCabelTV 和 LocalDishTV 保存在单独的 dll 文件中。我想知道如何在运行时加载这些类?我知道我们不会使用 switch 而是使用 for 循环来查找特定目录中实现 IVideoSource 接口的所有 dll 文件并加载这些文件...

需要了解如何动态加载 dll 并创建对象并使用它们的方法?

foreach (string dll in Directory.GetFiles("C:\DLLs\*.dll"))
{
    Assembly assemb = Assembly.LoadFrom(dll);
    ??
}

以下工作正常:

static void Main(string[] args)
{
   SmartTv myTv = new SmartTv();

   Console.WriteLine("Select A source to get TV Guide and Play");
   Console.WriteLine("1. Local Cable TV\n2. Local Dish TV");

   ConsoleKeyInfo input = Console.ReadKey();

   switch (input.KeyChar)
   {
      case '1':
          myTv.VideoSource = new LocalCabelTv();
          break;

      case '2':
          myTv.VideoSource = new LocalDishTv();
          break;
   }

   Console.WriteLine(); 

   myTv.ShowTvGuide();

   myTv.PlayTV();

   Console.ReadKey();
}


class SmartTv
    {
        IVideoSource currentVideoSource = null;

        public IVideoSource VideoSource
        {
            get
            {
                return currentVideoSource;
            }
            set
            {
                currentVideoSource = value;
            }
        }

        public void ShowTvGuide()
        {
            if (currentVideoSource != null)
            {
                Console.WriteLine(currentVideoSource.GetTvGuide());
            }
            else
            {
                Console.WriteLine("Please select a Video Source to get TV guide from");
            }
        }

        public void PlayTV()
        {
            if (currentVideoSource != null)
            {
                Console.WriteLine(currentVideoSource.PlayVideo());
            }
            else
            {
                Console.WriteLine("Please select a Video Source to play");
            }
        }


class LocalCabelTv : IVideoSource
    {
        const string SOURCE_NAME = "Local Cabel TV";

        string IVideoSource.GetTvGuide()
        {
            return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
        }

        string IVideoSource.PlayVideo()
        {
            return string.Format("Playing - {0}", SOURCE_NAME);
        }
    }


class LocalDishTv : IVideoSource
    {
        const string SOURCE_NAME = "Local DISH TV";

        string IVideoSource.GetTvGuide()
        {
            return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
        }

        string IVideoSource.PlayVideo()
        {
            return string.Format("Playing - {0}", SOURCE_NAME);
        }
    }

【问题讨论】:

标签: c# .net


【解决方案1】:

在运行时加载这个程序集并创建一个对象:

Assembly MyDALL = Assembly.Load("DALL"); // DALL is name of my dll
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // LoadClass is my class
object obj = Activator.CreateInstance(Type.GetType("DALL.LoadClass, DALL", true));

对于您的动态方法,您还可以使用 动态方法 。它比反射更快(这种方法只需要 Activator 所需的 1/10 时间。)

这是使用动态方法创建对象的示例代码。

void CreateMethod(ConstructorInfo target)
{
    DynamicMethod dynamic = new DynamicMethod(string.Empty,
                typeof(object),
                new Type[0],
                target.DeclaringType);

    methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}

查看以下链接了解更多信息:Load Assembly at runtime and create class instance

编辑:正如用户@taffer 提到的,DynamicMethod.CreateDelegate 比反射慢得多。因此,仅当创建的委托被调用数百或数千次时,我才会使用它。将 Activator 与缓存一起使用会更快。其次,Activator 对于无参构造函数来说确实很快,除非你实例化了这么多类型,这使得内部的小缓存毫无用处。

【讨论】:

  • 你不想用Reflection.Emit 生成代码,除非你真的必须……想想可怜的程序员会取代你并且必须学习这段代码……
【解决方案2】:

您需要加载带有所需类的 DLL 并迭代它们的类型,而不是寻找那些实现 IVideoSource 的 DLL 并激活它们:

public static IEnumerable<IVideoSource> GetVideoSources(List<string> assemblyPathes)
{
    IEnumerable<Assembly> yourAssembliesWithClasses = assemblyPathes.Select(x => Assembly.Load(x));

    IEnumerable<Type> implementingTypes = yourAssembliesWithClasses
        .GetTypes()
        .Where(x => x.IsAssignableFrom(IVideoSource));

    return implementingTypes.Select(x => Activator.CreateInstance(x));
}

注意Activator.CreateInstance() 要求类型有一个空的构造函数,如果它们没有你可以使用的,Type.GetUniGetUninitializedObject(Type type) from FormatterServices 来初始化它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2010-09-30
    • 2013-03-13
    相关资源
    最近更新 更多