开发者

How do I declare a list of types, and later instantiate one?

开发者 https://www.devze.com 2023-02-28 23:16 出处:网络
I have a case where I have some classes that each process a type of token.They all descend from a base handler class (simplified down a bit, so excuse any anti-compile typos):

I have a case where I have some classes that each process a type of token. They all descend from a base handler class (simplified down a bit, so excuse any anti-compile typos):

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

I also have a worker class where I'd like to store a list of these handlers, and later instantiate one of the handlers to process a开发者_如何学编程 token:

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;
      }
    }
  }
}

My question is, how do I handle the last foreach? Is this even possible - or is there a better way? I like the extensibility of being able to add new types in the future, just by adding them to the handlers list (or even passing them in from outside). I'm using c#, framework 3.5+.


It's not possible like this, no - because your list is a list of types, not references to instances of that type.

The closest you can easily come, assuming that there's a parameterless constructor for each type, is:

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;
   }
}

EDIT: In answer to your question in the comments, I would handle this slightly differently.

I would change your List<Type> to a List<Func<TokenKind, TokenClassBase>>. In other words, a list of factory functions, from TokenKind to TokenClassBase. The function for each type would depend on the type, but it would either return an instance of TokenClassBase, or null if that TokenKind couldn't be handled.

Then you'd use:

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

The way that you'd create the delegates would depend on the exact nature of your code, but you could either use a lambda expression or a method group conversion, probably from a static method.


You may want to look at the Activator.CreateInstance method.

Your loop would be

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

For the missing piece, you'd basically need a list of what tokens each type can handle. If it's a 1-1 relationship, you might consider a Dictionary<TokenKind,Type>. Or, to avoid reflection entirely, use a Dictionary<TokenKind,Func<TokenClassBase>> and each value is () => new TokenClass1().

Why do you want a list of types instead of a list of instances anyway?

0

精彩评论

暂无评论...
验证码 换一张
取 消