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

Let's say I have 3 DLLs (BlueCar, RedCar, YellowCar), each of which has a named class (BlueCarClass, etc.) that also implement the same interface, Car, and they are all built from the same same namespace (Car_Choices). Thus, before compiling the DLL looks something like this:

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 name will be "BlueCar.dll".

In the main program, the user selects what color of the car they need, and according to their choice, he dynamically loads only the corresponding DLL and runs What_Color (). The main program has a copy of the car interface. Now I have the following, but it does not work.

 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 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 any structural changes that I need to make (for example, place each color DLL in my own namespace)? Or I don’t understand how to properly load and use classes from a DLL.

EDIT: Here is a solution that I should work in case someone is looking for a more detailed answer.

PROJECT 1: common interface (as a class library) Car_Interface.cs

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

Compile the DLL link in Car_Interface.dll in the following two projects.

PROJECT 2: Implementation of the car interface as a class library BlueCar.cs

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

Compile to BlueCar_PlugIn.dll

PROJECT 3: Main program / driver 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 to bin (or where your program has ever been compiled) and run it, it will be able to dynamically load BlueCar_PlugIn.dll, but it does not have to run it (for example, if you have YellowCar_PlugIn.dll, and also RedCar_PlugIn.dll with similar implementations, you will need to download only one file for the program to work).

+5
source share
1 answer

Your code does not work, because, for example, BlueCarClass does not implement Car, which is in the application assembly, because the full name of the base classes is different. The Car class that is in your BlueCar assembly may have a full name

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

but the Car class that is in your application has a different full name, something like this

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

Even if you put the class in the same namespace, the full name is still different from the assembly name.

There are many ways to achieve the desired results: you can use MEF or you can create something easier on your own.

Your solution should have at least 3 assemblies:

  • Library of interfaces. It supports iCar interface.
  • Plugin library. (in your case, BlueCar, RedCar, etc.). It refers to library # 1.
  • Application. It explicitly references library # 1 and dynamically uses # 2.

PS Actually, you can do this using 2 assemblies, combining # 1 and # 3 and making # 2 link # 3 instead of # 1. It will work, however it is logically incorrect because you enter cross-references (implicitly). In my opinion, this approach smells.

+5
source

Source: https://habr.com/ru/post/1261521/


All Articles