2010-09-23 2 views
1

В C#, в настоящее время я делаю следующий код, чтобы отфильтровать определенный набор классов, которые наследуют от CaptureType, который передается методу.Более эффективный способ найти класс, наследующий интерфейс?

public static CaptureType[] ListPluginsWith<CaptureType>() 
    { 
     List<CaptureType> plugins = new List<CaptureType>(); 
     foreach (var plugin in Bot.AutoPlugins) 
     { 
      CaptureType plug; 
      try 
      { 
       if ((plug = (CaptureType)plugin.Interface) != null) 
       { 
        plugins.Add(plug); 
       } 
      } 
      catch 
      { 
       //doesn't inherit 
      } 
     } 
     return plugins.ToArray(); 
    } 

есть ли более эффективный/лучший/более быстрый способ сделать это? если да, то пожалуйста, дайте мне знать :)

ответ

4
if (plugin.Interface is CaptureType) 
{ 
    // inherits 
} 

или даже

return Bot.AutoPlugins.Where(i => i.Interface is CaptureType).ToArray(); 

UPD: если CaptureType настоятельно требуется возвратить:

return Bot.AutoPlugins.Where(i => i.Interface is CaptureType) 
         .Select(i => i as CaptureType) 
         .ToArray(); 

(да, теперь выглядит немного более раздутым, но есть еще один лаконичный ответ с OfType() в этой теме, поэтому я не буду его повторять)

+1

Обратите внимание, что ваша вторая версия фактически возвращает массив 'Plugin', а не' CaptureType'. Вам придется связать его с вызовом 'Select()'. –

+0

@Dean Harding: да, я видел это, но я уверен, что это подходящее решение тоже, и когда это необходимо - этот массив будет выпущен неявно. – zerkms

3

Я бы на самом деле предлагаю следующее:

public static IEnumerable<CaptureType> ListPluginsWith<CaptureType>() 
    where CaptureType : class 
{ 
    foreach (var plugin in Bot.AutoPlugins) 
    { 
     CaptureType plug = plugin.Interface as CaptureType; 
     if (plug != null) 
      yield return plug; 
    } 
} 

Это имеет ряд преимуществ:

  1. Если вы используете is ключевое слово, в основном в конечном итоге делает два слепков типа (оценки x is y - это, в основном, литье типов и имеет те же характеристики производительности), поэтому если вы делаете (if (x is Y) { blah = (Y)x }, вы делаете две броски вместо одного, что as и требуется проверка null.
  2. При использовании интратора (т. Е. yield return) вам не нужно создавать временную память List<CaptureType>, преобразовать ее в массив и затем вернуть массив.

Также обратите внимание на where CaptureType : class. Поскольку CaptureType - это интерфейс, вы можете быть уверены, что он всегда будет проходить, но это ограничение требуется для использования ключевого слова as. Если у вас есть «базовый» интерфейс, который реализуются всеми вашими плагинами (например, IPlugin), вы можете вместо этого заменить where CaptureType : class на where CaptureType : IPlugin.

+0

+1 для оценки эффективности ключевого слова as. –

+0

Я не могу использовать ключевое слово as, поскольку тип захвата будет интерфейсом, поэтому у меня не может быть где: class ... но спасибо за ваш ввод – caesay

+0

У меня есть интерфейс, который реализуются всеми моими плагинами, да, спасибо за это. – caesay

0

Я хотел бы предложить простой

return Bot.AutoPlugins.Select (p => p.Interface).OfType<CaptureType>().ToArray(); 

EDIT:

больше думать, что это потенциально менее эффективным, чем делать А, где затем выбрать комбинацию, как в моем примере вы делаете выбор для каждого элемента , то ограничение по типу ...

Смежные вопросы