调用没有反射的方法声明

时间:2010-01-28 14:54:24

标签: c# reflection methods polymorphism interface-implementation

我有一个基类(顺序)和一组子类(生产者,特殊订单,零件订单等)。

只有部分子类实现了一个特定的接口(ITrackingCustomer),它有一个方法声明(object getcustdetails())。

作为我的解决方案的一部分,我的所有订单都在中心位置处理,即任何crud方法都通过中心层。在这个中心层,我想做以下事情:

如果订单类型为ITrackingCustomer

然后调用方法getcustdetails()

我使用以下代码进行此操作:

if (typeof(ITrackingCustomer).IsAssignableFrom(Order.GetType())) 
{ 
     MethodInfo theMethod = Order.GetType().GetMethod("getcustdetails"); 
     object y = theMethod.Invoke(Order, null); 
} 

我对使用isassignablefrom的第一部分感到满意​​,但是对于第二部分(即使用调用的反射)使用性能较低的方法。

我的问题是:

是否有一种更有效的方法可以做到这一点,因为我已经读过使用invoke命令的代价很高。

4 个答案:

答案 0 :(得分:6)

ITrackingCustomer ord = Order as ITrackingCustomer;
if (ord != null)
{
    object y = ord.getcustdetails();
}

答案 1 :(得分:1)

你可以这样做:

if(Order is ITrackingCustomer) {
    ((ITrackingCustomer)Order).getcustdetails();
}

答案 2 :(得分:1)

正如其他人所提到的,您可以使用isas运算符来确定某个对象是否属于某种类型。但是,多态性通常更适合解决此类问题。

如果可行,也许您可​​以在getcustdetails()上放置Order方法。如果它具有合适的默认实现(即不返回任何详细信息或virtual),则设为null;如果所有abstract类型必须实现它,则设为Order。由于您具有ITrackingCustomer接口,因此我怀疑abstract方法无效。但是,对于实施Order的{​​{1}}类型,您可以相应地实施ITrackingCustomer

此时,听起来你可以取消使用getcustdetails(),但在不知道有关如何使用此界面的更多细节的情况下,我无法肯定地说。

完成此操作后,您将无需执行任何类型检查,因为调用ITrackingCustomer始终会调度到正确的具体实现。

答案 3 :(得分:0)

如果您尝试按名称进行呼叫而不是在界面中调用成员,并且您希望能够调用相同的方法数千次,那么除了演员之外(我假设您不能这样做,因为你不知道类型)或反射是JIT编译调用。

Rick Strahl有a nice blog article on调用方法的各种方法的性能成本,而评论导致this article显示了如何将委托拉出到非虚方法。

最后,我写了a blog article on how to build adapter classes on the fly。你可以做的就是创建一个符合抽象类的直接可调用对象:

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();

现在,我需要明确一点 - 只有两个理由这样做:

  1. 如果您在编译时知道目标参数并且不知道目标程序集,并且希望代码是CLEAN,那么您希望能够具有按名称调用语义。这方面的一个例子是知道它想要创建和使用特定对象的代码,但是不知道程序集在运行时是否可用并且禁止有引用。

  2. 您希望将对象方法称为反射,但希望快速,快速,快速地执行此操作,并将数千次或数百次调用它们。

  3. 如果这是一次“召唤一次”的事情,你最好不要写一个帮助方法去做你想做的事情。