|
Unfortunately, this implementation is not as easily achieved in C#. An instance of the Component Manager class cannot be passed to the plug in without having the Component Manager referenced in the plug-in’s assembly, and this defeats one of the purposes of component development—being able to eliminate build dependencies between components.
A simple proxy can similarly be implemented in C# using a delegate, which is actually a type of class. The proxy allows the plug-in to invoke back without requiring specific knowledge of the target interface. The following diagram illustrates the design.
Note that the only pre-requisite is that the plug-in have a defined entry point that the loader can use to initialize the application/plug-in interface.
using System; namespace Proxy { public delegate void Callback(string s); }This implementation must be placed in a DLL that is referenced in the application and plug-in projects.
using System; namespace PlugIn { public class PlugIn { public static void Test(Proxy.Callback cbck) { cbck("Success!"); } } }This is a very simple demonstration, in which the plug-in invokes a method in the application using a delegate.
public static MethodInfo GetMethodInfo(string reflection) { MethodInfo mi=null; string[] info=reflection.Split(new char[] {'/'}); Assembly mainAssembly=Assembly.LoadFrom(info[0]); Type type=mainAssembly.GetType(info[1]); mi=type.GetMethod(info[2]); return mi; }The plug-in is loaded and the Test method is acquired by calling the
GetMethodInfo
function:
mi=GetMethodInfo("PlugIn.dll/PlugIn.PlugIn/Test");
Note how the three components of an assembly are parsed, using ‘/’ as a separator.
The first component of an assembly is the file name;
The second component of an assembly is the namespace and class name;
The third component of an assembly is the method name.
private void CallbackTest(string s) { textBox1.Text=s; }
Proxy.Callback cbck=new Proxy.Callback(CallbackTest);
Test
method of the plug-in expects the delegate as a parameter. This is established by creating a parameter list:
object[] parms=new object[] {cbck};
The plug-in function is called using the reflection Invoke
method:
mi.Invoke(null, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Static, null, parms, null);
Click on the “Load Plug In” button to load the PlugIn.dll assembly.
Click on the “Invoke” button to call into the plug-in using reflection and to have the plug-in call back to the executable using the proxy delegate.
For simplicity, compile only in Debug mode. The projects are set up to place all the DLL’s in the ProxyDemo/bin/Debug directory.
Invoke
method is null, since there is no object on which to invoke the method (and in fact, this parameter is ignored for static method invocations). However, as demonstrated by this code, the delegate can reference a method associated with a specific instance.