Introduction
When developing frameworks to plug different components (specially in later stages), interfaces build the bridge between the framework and components. This article explains how to use an interface implemented in some other assembly to work as a late bound component to its calling framework. Besides, this illustrates the fundamental characteristics of interfaces as well.
Special thanks should go to Marc Clifton, author of Proxy Delegates, and recommend you all to have a look at his article for a better understanding on using proxy DLLs.
How it works....
As shown in the above diagram, Proxy is a DLL, which declares the common interface. Both Application and Component has reference to this proxy DLL and hence has the knowledge about the interface. Each component implements its own version of the common interface. Apart from interface implementation, it is required to have a means to instantiate the class that implements the interface inside the component. For this purpose, there is a separate class inside the component. By invoking a function in this secondly mentioned class using .NET reflection, the application obtains a reference to the interface, which could be used to manipulate the object instance.
Implementation
Demo project implements simple mathematical operations on two integers with interfaces. Functionality is trivial, but it still clearly explains the usage of interfaces.
IMath
is an interface with a single function CalcValues
, and it is declared in MathProxy.dll.
namespace MathProxy
{
public interface IMath
{
int CalcValues(int i1, int i2);
}
}
Using IMath
interface, PluginAdd
implements the Add
class.
public class Add : IMath
{
int IMath.CalcValues(int iValue1,int iValue2)
{
int iResult;
iResult = iValue1 + iValue2;
return iResult;
}
}
Now, there should be a way to create an instance of the Add
class. The code snippet below which resides in PluginAdd
, declares a class, which fulfills the requirement. (At this point, it is required to add a reference to MathProxy.dll).
public class CreateIntf
{
static Add m_add;
static public IMath Create()
{
m_add = new Add();
return m_add;
}
}
Now, let's have a look at how we are going to use these modules in an application. The two lines below show how to use .NET reflection in locating the assembly and the function to invoke. (Here the m_Math
is of type IMath
, not Add
). GetMethodInfo
function doses nothing, but fills the MethodInfo
class using the string
that is passed into it. Real method invocation take place in the second line and it returns a reference to the IMath
interface implementation (i.e. to Add
class in PluginAdd.dll).
MethodInfo mi=GetMethodInfo("PluginAdd.dll/PluginAdd.CreateIntf/Create");
m_Math = (IMath)mi.Invoke(null, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.InvokeMethod |
BindingFlags.Static, null, null, null);
Finally, there is a reference to the Add
object in PluginAdd
and all we have to do is call the functions in the interface as we wish. As shown below, the function CalcValues
is invoked using the m_Math
and the result is shown in a message box.
iRet = m_Math.CalcValues(10,20);
MessageBox.Show( iRet.ToString() );
Notes:
Eventhough I have described the implementation and usage of the PluginAdd assembly, the demo source code has PluginSub assembly, which illustrates a subtract operation using IMath
interface.
Application Framework to plug components - Part II will be available soon to explain how to notify the framework upon events.