I'm writing a program in C# (3.5 at the moment, but likely to be adaptable to other versions as the need arises) that uses a simple plugin architecture to control input and output. Each plugin is a DLL that is loaded when the user chooses the plugins to use.
Since the actual plugin class isn't known until run time, I'm using reflection in a wrapper class to call methods and access properties of the plugins.
Up until now, I've been using the following to call methods on a plugin:
public object Method(string methodName, params object[] arguments) {
// Assumed variables/methods/exceptions:
// Dictionary<string, MethodInfo> Methods: a cache of MethodInfo's
// of previously called methods.
// NoSuchMethodException: thrown if an unknown/unreachable method is
// requested. The message member contains the invalid method name
// void LoadMethod(string methodName, params object[] arguments): responsible
// for retrieving the MethodInfo's, or throw a NoSuchMethodException
// object Plugin: an instance of the dynamically loaded class.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return Methods[methodName].Invoke(Plugin, arguments);
}
Which is used like:
string[] headers = (string[]) Plugin.Method("GetHeaders", dbName, tableName);
This works nicely, as long as the caller correctly casts the return value to the expected type. Plugins must implement certain interfaces, so the caller should know this type.
After doing some further work with reflection however, the following alternate form occurred to me:
public T Method<T>(string methodName, params object[] arguments) {
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (Methods[methodName].ReturnType != typeof(T)) {
// Could also move this into LoadMethod to keep all the throwing in one place
throw new NoSuchMethodException(methodName);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return (T) Methods[methodName].Invoke(Plugin, arguments);
}
This one is used like:
string[] headers = Plugin.Method<string[]>("GetHeaders", dbName, tableName);
This version essentially moves the casting into the Method method. The caller obviously still needs to know the expected return type, but that was always going to be the case. It doesn't work for void methods, but I can include a version of Method for that:
public void Method(string methodName, params object[] arguments) {
// Good for void methods, or when you're going to throw away the return
// value anyway.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
Methods[methodName].Invoke(Plugin, arguments);
}
My question is - is one of these intrinsically better than the other (for a given value of 'better')? For instance, is one notably faster? Easier to understand? More supported?
I personally like the look of the latter, although I am a bit worried that my return type testing (Methods[methodName].ReturnType != typeof(T)
) might be too simplistic. Interestingly, it was originally !(Methods[methodName].ReturnType is T)
, but that always seemed to fail.
The closest existing question to this I could find was Generic method to type casting, and some of the answers suggested that the latter method is more expensive than the former, but there's not much in the way of detail there (the question there is more towards implementation of the method rather than which is better).
Clarification: This is a hand-rolled, very limited plugin system, not using IPlugin. I'm more interested in the question of whether generic methods are inherently better/worse than expecting the caller to cast in this situation.