I have some old C# plugin code that was implemented strictly with Reflection. In fixing some C# 2.0 -> 4.0 compatibility issues ("Load from Remote Source") I've decided to get rid of the old reflection code and replace it with an interface. The interface is needed because the Plugins now need to be loaded into their own AppDomain and then marshalled across.
I can go through the source for hundreds of plugins and simply make them all implement the new IPlugin
interface with a simple search-and-replace. This works nicely except in one crucial place. And I'm looking for an easy out.
The method RunPlugin()
can be implemented in one of two ways, but never both: Either with an argument or without. If I include this in the interface, I'd have to implement both in each of the plugins. The caller calls the one or no argument method based on which one is implemented. The calling assembly figures this out now by reflection.
To avoid that I can create a wrapper class for the plugins, that wrapper implements the interface, but then I'd have to heavily edit each of the plugins to include an override for each of the API's many methods.
Some sample code (this doesn't necessarily work! It's all in transition right now!):
The interface (sample):
// In IPlugin.cs / IPlugin.dll
namespace Plugin
{
public interface IPlugin
{
// Many, many happy API things like this...
void SetupOptions(Hashtable options);
// (examples elided)
// And then these two... either one or the other
// is implemented, but not both.
XmlDocument RunPlugin(Updater u);
XmlDocument RunPlugin();
}
}
The called Assembly... I have lots of these. I can add the ": IPlugin" fairly easily. This won't compile, obviously, because it doesn't implement the one-argument RunPlugin()
.
namespace Plugin
{
public class FileMaintenance : IPlugin
{
public void SetupOptions(Hashtable options)
{ // Code elided
}
public XmlDocument RunPlugin()
{ // Code elided
}
}
}
And finally, the calling code. This is actually how it used to look, back in the reflection code:
public XmlDocument RunPlugin(PluginRunner.Updater u)
{
Type [] paramTypes = new Type [0];
MethodInfo runInfo = repType.GetMethod("RunPlugin", paramTypes);
if (runInfo == null)
{
paramTypes = new Type [1];
paramTypes[0] = u.GetType();
runInfo = repType.GetMethod("RunPlugin", paramTypes);
if (runInfo == null)
throw new Exception;
}
Object[] parameters;
if ( paramTypes.Length == 0)
parameters = new Object[0];
else
{
parameters = new Object[1];
parameters[0] = u;
}
Object returnVal;
try
{
returnVal = runInfo.Invoke(repObj,parameters);
}
catch (Exception e)
{
}
// Rest of code omitted
}
Remember: I'm looking for a nice balance between the right way to fix this old code, and doing the minimal amount of editing code by hand.