Click here to Skip to main content
15,922,166 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Okay, so I am trying to get an applet plugin style editor interface for a project of mine and I need to be able to cast a custom class that is referenced in both the main project and in the external applet template. I can use Assembly to load the dll file and get the UserControl out, but there are properties and methods in the class. I cannot cast the class to the custom UserControl without an InvalidCastException. Here is the code:
C#
//Get Name
string AppletName = AppletPaths[i].Replace(Application.StartupPath + "\\Applets\\", "");
//Get Assembly
Assembly asm = Assembly.LoadFile(AppletLocation);
Type type = asm.GetType("Example.AppletUI");

var obj = Activator.CreateInstance(type);
Example.AppletUI applet = (Example.AppletUI)obj;
Posted

1 solution

This code is too bad to discuss. Did you run it under Debugger? First, just look at the first line. You replace some directory with empty string. Why?! (By the way, don't use "", use string.Empty.) What's the purpose of AppletName then?

Now, a bad thing is using GetType by the class name. How can you support it? What if you decide to change the class name? You will certainly need to change it in more than one place, which is a big programming no-no. (If you don't understand it, read http://en.wikipedia.org/wiki/Don%27t_repeat_yourself[^].) Main problem here is this: if the type name is misspelled, compiler won't help you to detect the problem. That's why any immediate constants should be avoided by all means, especially string. With good programming style, it's easy to avoid. (Of course I don't count some constants used everywhere like 0, 1 and null.)

This method is not really designed for activation of plug-in implementations. Why doing this if there is a nice method to find and activate plug-in class without any constants at all. This approach is very simple: define some interface which a plug-in should implement. The host application can load an assembly and check all top-level classes which meet the following criteria: such class should implement the required plug-in interface and a parameterless constructor (or a constructor of some required signature).

I make one more step to avoid testing all types: I define an assembly-level attribute which is used to claim "this assembly implements the plug-in interface IPlugin (for example) in the class A (using typeof)". The host application uses Reflection to check up just one class (or a set of classes, because the same assembly could be uses as a plug-in of more than one type). To see an example on how to apply assembly-level attribute, look at you AssemblyInfo.cs file. The host application should checkup each plug-in assembly and plug-in implementation type for consistency. If the plug-in does not meet required criteria (such as only one implementation, existence of at least on implementation, match between implementation and claim attribute, etc.) and act accordingly if there is a inconsistency which could be considered as a warning or a fatal error.

I described this technique in further detail in my past solutions. Please see:
Create WPF Application that uses Reloadable Plugins...[^],
AppDomain refuses to load an assembly[^].

For more special uses of plug-ins, see:
code generating using CodeDom[^],
Create WPF Application that uses Reloadable Plugins...[^].

A simple case is explained here: Dynamically Load User Controls[^].

I apologize for the cases which may be much more advanced then you might need. The problem is in reloadable plug-ins. As unloading of a loaded assembly is not allowed by .NET, Application Domains and work with IPC across the Application Domain boundaries should be used. If you only need to load plug-ins without a need to unload them during run time, you can ignore this aspect.

—SA
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900