如何动态加载DLL并在其中使用一个类(实现一个已知的接口)[C#]

时间:2016-12-19 18:05:25

标签: c# dll interface

假设我有3个DLL(BlueCar,RedCar,YellowCar),每个DLL都有一个命名类(BlueCarClass等),它们也都实现了相同的接口Car,并且都是从同一个命名空间构建的( Car_Choices)。所以DLL在编译之前看起来像这样:

namespace Car_Choices
{
    public interface Car
    {
        void What_Color();
    }

    public class BlueCarClass : Car
    {
        public void What_Color()
        {
            MessageBox.Show('The color is blue.');
        }
    }
}

DLL的名称将是" BlueCar.dll"。

在主程序中,用户选择他们想要的汽车颜色,并根据他们的选择动态仅加载相应的DLL并运行What_Color()。主程序有一个Car接口的副本。现在我有以下内容,但它没有用。

static void Main()
{
    string car_choice = win_form_list.ToArray()[0]; //gets choice from a drop down
    Assembly car_assembly = Assembly.Load(car_choice); //car_choice is BlueCar
    Type car_type = car_assembly.GetType("Car");
    Car car = Activator.CreateInstance(type) as Car;
    car.What_Color();
}

我也试过

static void Main()
{
    string car_choice = win_form_list.ToArray()[0]; //gets choice from a drop down
    ObjectHandle car_handle = Activator.CreateInstance(assembly_name, "Car_Choices."+ car_choice);
    Car car= (Car)handle.Unwrap();
    car.What_Color();
}

有任何帮助吗?是否需要进行结构更改(例如将每个汽车颜色DLL放入其自己的命名空间中)?或者我不理解如何正确加载和使用DLL中的类。

编辑:这是我开始工作的解决方案,以防有人在寻找更详细的答案。

PROJECT 1:共享接口(作为类库) Car_Interface.cs

namespace Car_Interface
{
    public interface ICar_Interface
    {
        char Start_Car();
    }
}

编译成Car_Interface.dll,在接下来的2个项目中引用DLL。

PROJECT 2:Car接口实现,作为类库 BlueCar.cs

namespace BlueCar_PlugIn
{
    public class BlueCar : Car_Interface.ICar_Interface
    {
        public char Start_Car()
        {
            MessageBox.Show("Car is started");
        }
    }
}

编译成BlueCar_PlugIn.dll

项目3:主程序/驱动程序 Program.cs的

namespace Main_Program
{
    public class Program
    {
        static void Main()
        {
            Assembly assembly = Assembly.Load(DLL_name); //Where DLL_name is the DLL you want to load, such as BlueCar_PlugIn.dll
            Type type = (Type)assembly.GetTypes().GetValue(0); //Class that implements the interface should be first. A resource type could also possibly be found
            //OR
            Type type = (Type)assembly.GetType(DLL_name + class_name); //In this case, BlueCar_PlugIn.BlueCar
            Car_Interface.ICar_Interface new_car = (Car_Interface.ICar_Interface)Activator.CreateInstance(type);
            new_car.Start_Car();
        }
    }
}

现在,如果您将两个DLL移动到bin(或编译到的程序)并运行它,它将能够动态加载BlueCar_PlugIn.dll但不一定需要它运行(例如,如果你有类似实现的YellowCar_PlugIn.dll和RedCar_PlugIn.dll,只需要加载一个程序即可运行。

1 个答案:

答案 0 :(得分:5)

您的代码不起作用,例如, BlueCarClass 未实现应用程序集中的 Car ,因为基类的完全限定名称不同。 BlueCar程序集中的类 Car 可能具有完全限定名称

BlueCar.Car,BlueCar,Version = 1.0.0.0,Culture = neutral,PublicKey = null

但应用程序中的类 Car 具有不同的完全限定名称,如下所示

SomeApp.Car,SomeApp,Version = 1.0.0.0,Culture = neutral,PublicKey = null

即使您将类放在同一名称空间中,全名仍然不同,因为它包含程序集名称。

有多种方法可以达到您想要的结果:您可以使用MEF,也可以自己创建更轻量级的内容。

您的解决方案需要至少有3个程序集:

  1. 接口库。这保留了ICar界面。
  2. 插件库。 (在你的情况下,BlueCar,RedCar等)。它引用了库#1。
  3. 应用。它显式引用库#1并动态使用#2。
  4. PS实际上你可以通过合并#1和#3使用2个程序集来做到这一点,并使#2引用#3而不是#1。它会起作用,但它在逻辑上是不正确的,因为你引入了交叉引用(隐式)。在我看来,这种方法闻起来。