如何声明类型列表,稍后实例化一个?

时间:2011-04-24 19:26:30

标签: c# class list types reference

我有一个案例,我有一些类,每个类都处理一种令牌。它们都来自一个基本处理程序类(简化了一下,所以请原谅任何反编译错别字):

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

我还有一个worker类,我想存储这些处理程序的列表,然后实例化其中一个处理程序来处理一个令牌:

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 个答案:

答案 0 :(得分:6)

不可能这样,不 - 因为你的列表是类型的列表,而不是对该类型的实例的引用。

假设每种类型都有无参数构造函数,那么最接近的就是:

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>>。换句话说,工厂功能列表,从TokenKindTokenClassBase。每种类型的函数都取决于类型,但如果{{1> TokenClassBase无法处理。

然后你会使用:

null

您创建委托的方式取决于代码的确切性质,但您可以使用lambda表达式或方法组转换,可能来自静态方法。

答案 1 :(得分:3)

您可能需要查看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()

为什么你想要一个类型列表而不是一个实例列表呢?