Как мне объявить список типов, а затем создать его экземпляр? - PullRequest
2 голосов
/ 24 апреля 2011

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

public abstract class TokenClassBase
{
  public static bool HandlesTokenType(TokenKind AType)
  {
    return handledTokens.Contains(AType);
  }
  protected virtual void HandleToken(AToken)
  {
  }
}

public class TokenClass1 : TokenClassBase
{
  public static new bool HandlesTokenType(TokenKind AKind)
  {
    return AKind == TokenKind.type1;
  }
  public override void HandleToken(AToken)
  {
  //do some work
  }

}
// public class TokenClass2... etc

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

public class MyWorker
{
  private List<Type> handlers;
  public MyWorker()
  {
    handlers = new List<Type>;
    handlers.Add(typeof(TokenClass1));
    handlers.Add(typeof(TokenClass2));
    //... etc
  }
  protected virtual void HandleToken(AToken)
  {
    foreach (TokenBaseClass handler in handlers)
    {
      if (handler.HandlesToken(AToken))
      {
        instantiate(handler);
        handler.HandleToken(AToken);
        break;
      }
    }
  }
}

Мой вопрос: как мне обработать последний foreach?Это вообще возможно - или есть лучший способ?Мне нравится возможность добавления новых типов в будущем, просто добавляя их в список обработчиков (или даже передавая их извне).Я использую c #, рамки 3.5 +.

Ответы [ 2 ]

6 голосов
/ 24 апреля 2011

Это невозможно, нет, потому что ваш список представляет собой список типов , а не ссылок на экземпляров этого типа.

Ближайший, который вы можете легко найти, если предположить, что для каждого типа есть конструктор без параметров:

foreach (Type handlerType in handlers)
{
   // Create an instance of the handler type
   TokenBaseClass handler = 
       (TokenBaseClass) Activator.CreateInstance(handlerType);
   if (handler.HandlesToken(AToken))
   {
     handler.HandleToken(AToken);
     break;
   }
}

РЕДАКТИРОВАТЬ: В ответ на ваш вопрос в комментариях, я бы отнесся к этому немного по-другому.

Я бы изменил ваш List<Type> на List<Func<TokenKind, TokenClassBase>>. Другими словами, список фабричных функций, от TokenKind до TokenClassBase. Функция для каждого типа будет зависеть от типа, но она будет либо возвращать экземпляр TokenClassBase, или null, если это TokenKind не может быть обработано.

Тогда вы будете использовать:

foreach (var handlerFactory in handlerFactories)
{
    TokenBaseClass handler = handlerFactory(AToken);
    if (handler != null)
    {
        handler.HandleToken(AToken);
        break;
    }
}

Способ создания делегатов будет зависеть от точной природы вашего кода, но вы можете использовать лямбда-выражение или преобразование группы методов, возможно из статического метода.

3 голосов
/ 24 апреля 2011

Возможно, вы захотите взглянуть на метод Activator.CreateInstance.

Ваш цикл будет

foreach (Type handlerType in handlers)
{
  if (...not sure how you'd do this part...)
  {
    TokenBaseClass handler = (TokenBaseClass)Activator.CreateInstance(handlerType);
    handler.HandleToken(AToken);
    break;
  }
}

Для недостающего фрагмента вам, в основном, понадобится список токенов, с которыми может работать каждый тип. Если это отношение 1-1, вы можете рассмотреть Dictionary<TokenKind,Type>. Или, чтобы полностью избежать отражения, используйте Dictionary<TokenKind,Func<TokenClassBase>> и каждое значение будет () => new TokenClass1().

Зачем вам нужен список типов вместо списка экземпляров?

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