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?
精彩评论