我有一个基类(顺序)和一组子类(生产者,特殊订单,零件订单等)。
只有部分子类实现了一个特定的接口(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命令的代价很高。
答案 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)
正如其他人所提到的,您可以使用is
和as
运算符来确定某个对象是否属于某种类型。但是,多态性通常更适合解决此类问题。
如果可行,也许您可以在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();
现在,我需要明确一点 - 只有两个理由这样做:
如果您在编译时知道目标参数并且不知道目标程序集,并且希望代码是CLEAN,那么您希望能够具有按名称调用语义。这方面的一个例子是知道它想要创建和使用特定对象的代码,但是不知道程序集在运行时是否可用并且禁止有引用。
您希望将对象方法称为反射,但希望快速,快速,快速地执行此操作,并将数千次或数百次调用它们。
如果这是一次“召唤一次”的事情,你最好不要写一个帮助方法去做你想做的事情。