вызов метода без отражения - PullRequest
2 голосов
/ 28 января 2010

У меня есть базовый класс (заказ) с набором подклассов (продюсер, спецзаказ, запчасть и т. Д.).

Только некоторые из этих подклассов реализуют определенный интерфейс (ITrackingCustomer), который имеет одно объявление метода (объект getcustdetails ()).

Как часть моего решения, все мои заказы обрабатываются в центральном месте, то есть любые грубые методы проходят через центральный слой. В этом центральном слое я хочу сделать следующее:

Если заказ имеет тип ITrackingCustomer

Затем вызывает метод getcustdetails ()

У меня это работает, используя следующий код:

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

Я доволен первой частью, использующей isassignablefrom, но хотел бы использовать менее интенсивный метод для второй части (то есть отражение с помощью invoke).

Мой вопрос:

Есть ли более эффективный способ сделать это, поскольку я прочитал, что использование команды invoke является дорогостоящим.

Ответы [ 4 ]

6 голосов
/ 28 января 2010
ITrackingCustomer ord = Order as ITrackingCustomer;
if (ord != null)
{
    object y = ord.getcustdetails();
}
1 голос
/ 28 января 2010

Как уже упоминалось, вы можете использовать операторы is и as, чтобы определить, принадлежит ли объект определенному типу. Однако полиморфизм обычно лучше подходит для решения этого типа проблем.

Если это возможно, возможно, вы можете разместить метод getcustdetails() на Order. Сделайте его virtual, если он имеет подходящую реализацию по умолчанию (т.е. не возвращает подробностей, или null), или abstract, если имеет смысл, что все типы Order должны его реализовывать. Поскольку у вас есть интерфейс ITrackingCustomer, я подозреваю, что метод abstract не будет работать хорошо. Однако для Order типов, которые реализуют ITrackingCustomer, вы можете реализовать getcustdetails() соответственно.

На данный момент, похоже, что вы могли бы покончить с ITrackingCustomer, но я не могу сказать наверняка, не зная более подробной информации о том, как используется этот интерфейс.

Как только это будет сделано, вам не нужно будет выполнять какие-либо проверки типов, так как вызов Order.getcustdetails() всегда отправляет правильную конкретную реализацию.

1 голос
/ 28 января 2010

Вы можете сделать:

if(Order is ITrackingCustomer) {
    ((ITrackingCustomer)Order).getcustdetails();
}
0 голосов
/ 28 января 2010

Если вы пытаетесь сделать вызов по имени вместо вызова члена в интерфейсе, и вы хотите иметь возможность вызывать один и тот же метод тысячи раз, то не для приведения (что, я полагаю, вы не можете сделать, потому что вы не знаете тип) или отражение JIT компилировать вызов.

У Рика Страля есть прекрасная статья в блоге о затратах на производительность различных способов вызова метода, а комментарии приводят к этой статье , которая показывает, как вывести делегата не метод.

Наконец, я написал статью в блоге о том, как создавать классы адаптера на лету . С этим вы можете сделать непосредственно вызываемый объект, который соответствует абстрактному классу:

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. вы хотите вызывать методы объекта как отражение, но хотите делать это быстро, быстро, быстро и будете вызывать их тысячи или миллионы раз.

Если это вызов "один раз", вам лучше написать вспомогательный метод, который будет делать то, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...