I have a base class (order) with a set of sub classes (productorder, specialorder, partsorder etc).
Only Some of these sub classes implement a particular interface (ITrackingCustomer) which has a single method declaration (object getcustdetails()).
As part of my solution all of my orders are processed in a central place, i.e. any crud methods pass through a central layer. Within this central layer I want to do the following:
If order is of type ITrackingCustomer
Then invoke method getcustdetails()
I have this working using the following code:
if (typeof(ITrackingCustomer).IsAssignableFrom(Order.GetType()))
{
MethodInfo theMethod = Order.GetType().GetMethod("getcustdetails");
object y = theMethod.Invoke(Order, null);
}
I am happy with t开发者_开发百科he first part using isassignablefrom but would like to use a less performance intensive method for the second part (i.e. the reflection using invoke).
My question is:
Is there a more efficient way of doing this as I have read that using the invoke command is costly.
ITrackingCustomer ord = Order as ITrackingCustomer;
if (ord != null)
{
object y = ord.getcustdetails();
}
You can do:
if(Order is ITrackingCustomer) {
((ITrackingCustomer)Order).getcustdetails();
}
As others have mentioned, you can use the is
and as
operators to determine if an object is of a certain type. However, polymorphism is usually better suited for solving this type of problem.
If it is feasible, perhaps you can place a getcustdetails()
method on Order
. Make it virtual
if it has a suitable default implementation (i.e. return no details or null
), or abstract
if it makes sense that all Order
types must implement it. Since you have the ITrackingCustomer
interface, I suspect that an abstract
method won't work well. However, for Order
types that implement ITrackingCustomer
, you can then implement getcustdetails()
accordingly.
At this point, it sounds like you would be able to do away with ITrackingCustomer
, but I can't say for certain without knowing more details about how this interface is used.
Once this is done, you won't need to perform any type checks since calling Order.getcustdetails()
always dispatches to the correct concrete implementation.
If you are trying to do call by name instead of invoking a member in an interface and you want to be able to call the same method thousands of times, then other than a cast (which I assume you can't do because you don't know the type) or reflection is to JIT compile the call.
Rick Strahl has a nice blog article on the performance costs of various ways to call method and the comments lead to this article which shows how to pull a delegate out to a non-virtual method.
Finally, I wrote a blog article on how to build adapter classes on the fly. What you can do with that is make a directly callable object that meets an abstract class:
public abstract class CustomerDetailsGetter {
public abstract object getcustdetails();
}
// ...
AdapterCompiler compiler = new AdapterCompiler();
AdapterFactory<CusomterDetailsGetter> factory = compiler.DefineAdapter<CustomerDetailsGetter>(Order.GetType());
// now, my code assumes you want to construct an object from whole cloth
// but the code could be changed to invoke the default constructor and set the
// adapted object.
CustomerDetailsGetter getter = factory.Construct(null)
object info = getter.getcustdetails();
Now, I need to be clear - there are only two reasons to do this:
you want to be able to have call-by-name semantics when you know the target arguments at compile time and you don't know have the target assembly, and you want your code to be CLEAN. An example of this is code that knows it wants to create and use a particular object, but doesn't know if the assembly will be available until run time and is forbidden to have a reference.
you want to call object methods a la reflection, but want to do this fast, fast, fast and will be calling them thousands or millions of times.
If it's a "call once" thing, you're way better off writing a helper method to do what you want.
精彩评论