2011-04-24 55 views
2

我有一个情况,我有一些类,每个类都处理一个令牌。他们都从一个基本处理程序类下降(简化了一点,所以请原谅任何反编译错别字):如何声明类型列表,并稍后实例化?

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+。

回答

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。每种类型的功能将取决于类型,但它会要么返回TokenClassBasenull实例如果TokenKind无法处理。

然后你会使用:

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

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

+0

你也可以让处理程序实现ICloneable(如果你想根据'serivce请求'克隆一个实例) – sehe 2011-04-24 19:31:42

+0

@sehe:是的,但你仍然需要一个实例列表,而不是一个类型列表。 – 2011-04-24 19:34:50

+0

啊哈,我误解了你的评论,并且认为这些类型已经被他们的实例存储了。读得太快了,斯里。仍然ICloneable环在这里主题:) – sehe 2011-04-24 19:37:53

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()

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