简体   繁体   English

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

[英]How to dynamically load a DLL and use a class in it (that implements a known interface) [C#]

Let's say I have 3 DLLs (BlueCar, RedCar, YellowCar) that each have a named class (BlueCarClass, etc) that also all implement the same interface, Car, and are all built from the same namespace (Car_Choices). 假设我有3个DLL(BlueCar,RedCar,YellowCar),每个DLL都有一个命名类(BlueCarClass等),它们也都实现了相同的接口Car,并且都是从相同的命名空间(Car_Choices)构建的。 So a DLL looks something like this before compiled: 因此,DLL在编译之前看起来像这样:

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

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

And the DLL's name would be "BlueCar.dll". DLL的名称将为“ BlueCar.dll”。

In the main program, the user selects which ever car color they want, and based on their choice it dynamically loads only the appropriate DLL and runs What_Color(). 在主程序中,用户选择他们想要的汽车颜色,并根据其选择仅动态加载适当的DLL并运行What_Color()。 The main program has a copy of the Car interface. 主程序具有Car接口的副本。 Right now I have the following, but it's not working. 现在,我有以下内容,但是它不起作用。

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();
}

I've also tried 我也尝试过

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();
}

Any help? 有什么帮助吗? Are there structural changes I need to make (such as putting each car color DLL in it's own namespace)? 我是否需要进行结构上的更改(例如将每个汽车颜色DLL放入其自己的名称空间中)? Or am I not understanding how to load and use classes from DLLs appropriately. 还是我不了解如何从DLL中正确加载和使用类。

EDIT: Here's the solution that I got to work, in case anyone is looking for a more detailed answer. 编辑:这是我必须使用的解决方案,以防有人在寻找更详细的答案。

PROJECT 1: The shared interface (as a Class library) Car_Interface.cs 项目1:共享接口(作为类库)Car_Interface.cs

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

Compile into Car_Interface.dll, reference DLL in next 2 projects. 编译为Car_Interface.dll,在接下来的2个项目中引用DLL。

PROJECT 2: Car interface implementation, as a class library BlueCar.cs 项目2:汽车接口实现,作为类库BlueCar.cs

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

Compile into BlueCar_PlugIn.dll 编译成BlueCar_PlugIn.dll

PROJECT 3: Main program/driver Program.cs 项目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();
        }
    }
}

Now if you move both DLLs into bin (or where ever your program is compiled to) and run it, it'll be able to dynamically load BlueCar_PlugIn.dll but not neccessarily need it to run (ex, if you have YellowCar_PlugIn.dll and also RedCar_PlugIn.dll with similar implementations, only one will need to be loaded for the program to work). 现在,如果将两个DLL都移到bin(或将程序编译到的任何位置)中并运行它,它将能够动态加载BlueCar_PlugIn.dll,但不必运行它(例如,如果您有YellowCar_PlugIn.dll和也具有类似实现的RedCar_PlugIn.dll,只需加载一个程序即可运行。

Your code does not work because, for example, BlueCarClass does not implement Car that is in the application assembly because the fully qualified name of base classes are different. 您的代码不起作用,因为例如, BlueCarClass不实现应用程序程序集中的Car ,因为基类的完全限定名称不同。 The class Car that is in your BlueCar assembly may have fully qualified name BlueCar装配中的Class Car可能具有完全合格的名称

BlueCar.Car, BlueCar, Version=1.0.0.0, Culture=neutral, PublicKey=null BlueCar.Car,BlueCar,版本= 1.0.0.0,文化=中性,公钥=空

but the class Car that is in your application has different fully qualified name, something like this 但是您的应用程序中的Car类具有不同的完全限定名称,例如:

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

Even though you put the class to the same namespace, the full name is still different because it include assembly name. 即使将类放在相同的名称空间中,全名仍然是不同的,因为它包含程序集名称。

There are many ways of how to achieve results that you want: you can use MEF or you can create something more lightweight by yourself. 有多种方法可以实现所需的结果:可以使用MEF ,也可以自己创建更轻量的内容。

Your solution needs to have at least 3 assemblies: 您的解决方案至少需要3个程序集:

  1. Interface library. 接口库。 That keeps ICar interface. 保留ICar接口。
  2. Plugin library. 插件库。 (in your case BlueCar, RedCar etc). (在您的情况下为BlueCar,RedCar等)。 It references the library #1. 它引用了库#1。
  3. Application. 应用。 It explicitly references library #1 and dynamically uses #2. 它显式引用库1,并动态使用库2。

PS Actually you can do this using 2 assemblies by merging #1 and #3 and make #2 reference #3 instead of #1. PS实际上,您可以通过合并#1和#3并使用#2引用#3而不是#1来使用2个程序集来执行此操作。 It will work, however its logically incorrect because you introduce cross references (implicitly). 它将起作用,但是由于在逻辑上不正确,因为您引入了交叉引用。 In my opinion this approach smells. 我认为这种方法很香。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM