I asked a question yesterday regarding using either reflection or Strategy Pattern for dynamically calling methods.
However, since then I have decided to change the methods into individual classes that implement a common interface. The reason being, each class, whilst bearing some similarities also perform certain methods unique to that class.
I had been using a strategy as such:
switch (method)
{
case "Pivot":
return new Pivot(originalData);
case "GroupBy":
return new GroupBy(originalData);
case "Standard deviation":
return new StandardDeviation(originalData);
case "% phospho PRAS Protein":
return new PhosphoPRASPercentage(originalData);
case "AveragePPPperTreatment":
return new AveragePPPperTreatment(originalData);
case "AvgPPPNControl":
return new AvgPPPNControl(originalData);
case "PercentageInhibition":
return new PercentageInhibition(originalData);
default:
throw new Exception("ERROR: Method " + method + " does not exist.");
}
However, as the number of potential classes grow, I will need to keep adding new ones, thus breaking the closed for modification rule.
Instead, I have used a solution as such:
var test = Activator.CreateInstance(null, "MBDDXDataViews."+ _class);
ICalculation instance = (ICalculation)test.Unwrap();
return instance;
Effectively, the _class parameter is the name of the class passed in at runtime. Is this a common way to do this, will there be any performance issues with this?
I am fairly new to reflection, so your advice would be welcome.
When using reflection you should ask yourself a couple of questions first, because you may end up in an over-the-top complex solution that's hard to maintain:
dynamic
invocations (only .NET 4.0 and above)?Genericity / dynamic
From your description I assume you do not know the types at compile time, you only know they share the interface
ICalculation
. If this is correct, then number (1) and (2) above are likely not possible in your scenario.Performance
This is an important question to ask. The overhead of using reflection can impede a more than 400-fold penalty: that slows down even a moderate amount of calls.
The resolution is relatively easy: instead of using
Activator.CreateInstance
, use a factory method (you already have that), look up theMethodInfo
create a delegate, cache it and use the delegate from then on. This yields only a penalty on the first invocation, subsequent invocations have near-native performance.Combine technologies
A lot is possible here, but I'd really need to know more of your situation to assist in this direction. Often, I end up combining
dynamic
with generics, with cached reflection. When using information hiding (as is normal in OOP), you may end up with a fast, stable and still well-extensible solution.Losing compile time type safety
Of the five questions, this is perhaps the most important one to worry about. It is very important to create your own exceptions that give clear information about reflection mistakes. That means: every call to a method, constructor or property based on an input string or otherwise unchecked information must be wrapped in a try/catch. Catch only specific exceptions (as always, I mean: never catch
Exception
itself).Focus on
TargetException
(method does not exist),TargetInvocationException
(method exists, but rose an exc. when invoked),TargetParameterCountException
,MethodAccessException
(not the right privileges, happens a lot in ASP.NET),InvalidOperationException
(happens with generic types). You don't always need to try to catch all of them, it depends on the expected input and expected target objects.To sum it up
Get rid of your
Activator.CreateInstance
and use MethodInfo to find the factory-create method, and useDelegate.CreateDelegate
to create and cache the delegate. Simply store it in a staticDictionary
where the key is equal to the class-string in your example code. Below is a quick but not-so-dirty way of doing this safely and without losing too much type safety.Sample code
One strategy that I use in cases like this is to flag my various implementations with a special attribute to indicate its key, and scan the active assemblies for types with that key:
That way, just by creating a new class with a new key string, you can automatically "plug in" to the factory, without having to modify the factory code at all.
You'll also notice that rather than depending on each implementation to provide a specific constructor, I've created an Initialize method on the interface I expect the classes to implement. As long as they implement the interface, I'll be able to send the "originalData" to them without any reflection weirdness.
I'd also suggest using a dependency injection framework like Ninject instead of using Activator.CreateInstance. That way, your operation implementations can use constructor injection for their various dependencies.
I suggest you give your factory implementation a method
RegisterImplementation
. So every new class is just a call to that method and you are not changing your factories code.UPDATE:
What I mean is something like this:
Create an interface that defines a calculation. According to your code, you already did this. For the sake of being complete, I am going to use the following interface in the rest of my answer:
Your factory will look something like this:
This simple factory class is lacking error checking for the reason of simplicity.
UPDATE 2:
You would initialize it like this somewhere in your applications initialization routine:
Essentially, it sounds like you want the factory pattern. In this situation, you define a mapping of input to output types and then instantiate the type at runtime like you are doing.
Example:
You have X number of classes, and they all share a common interface of IDoSomething.
Just as an example how to add initialization in the constructor:
Something similar to:
but written with Linq Expression, part of code is taken here:The usage is following:
The same can be implemented with DynamicMethods.
Also, the classes are not required to be inherited from the same interface or base class.
Thanks, Vitaliy