views:

119

answers:

4

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 the 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.

+1  A: 

You can do:

if(Order is ITrackingCustomer) {
    ((ITrackingCustomer)Order).getcustdetails();
}
Mattias Jakobsson
Always prefer `as` is this case...
Romain Verdier
Yes, I agree. That is a better option. I wrote quick without thinking to much :)
Mattias Jakobsson
+5  A: 
ITrackingCustomer ord = Order as ITrackingCustomer;
if (ord != null)
{
    object y = ord.getcustdetails();
}
LukeH
+1  A: 

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.

Steve Guidi
Hi thanks for the response, yeh u geussed right I cannot use virtual methods as the base class is code generated by wcfria and thus the interface. Cheers though I perhaps should have mentioned.
steve
A: 

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:

  1. 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.

  2. 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.

plinth
Hi,Tyhanks for the response, whilst this is not exactly what I am looking for here, looking at your blog this will definetly be useful in other areas of the project.Thanks....
steve