不幸的是,没有办法很好地做到这一点。如果您可以控制Template<'T>
类型,那么最好的选择是创建一个非通用接口(例如ITemplate
)并在Template<'T>
类型中实现该接口。然后,你可以检查接口:
| :? ITemplate as t -> ...
如果不是的话,那么你唯一的选择是使用一些魔法反射。您可以实现一个活动模式,该类型与某些Template<'T>
值相匹配,并返回用作一般参数的类型列表(System.Type
对象)。在你的伪代码,你想获得这个作为泛型类型参数'a
- 这是不可能得到,随着编译时类型参数,但你可以得到的运行时类型信息:
let (|GenericTemplate|_|) l =
let lty = typeof<list<int>>.GetGenericTypeDefinition()
let aty = l.GetType()
if aty.IsGenericType && aty.GetGenericTypeDefinition() = lty then
Some(aty.GetGenericArguments())
else
None
现在,您可以编写以下模式匹配代码:
match result with
| GenericTemplate tys ->
// ...
最后一个问题是 - 你怎么可以使用这个运行时类型信息来运行一些通用的代码。我能想到的最佳选择是使用反射调用通用方法(或函数) - 然后您可以将运行时类型信息指定为通用参数,因此代码可以是通用的。最简单的方法是调用类的静态成员:
type TemplateHandler =
static member Handle<'T>(arg:Template<'T>) =
// This is a standard generic method that will be
// called from the pattern matching - you can write generic
// body of the case here...
"aaa"
| :? GenericTemplate tys ->
// Invoke generic method dynamically using reflection
let gmet = typeof<TemplateHandler>.GetMethod("Handle").MakeGenericMethod(tys)
gmet.Invoke(null, [| result |]) :?> string // Cast the result to some type
关键的想法是,你移动模式匹配的身体(不能有泛型类型参数)到一个方法(即可以有泛型类型参数)并使用反射动态运行该方法。
您可以更改代码以使用let
函数而不是static member
- 使用反射来查找函数只会稍微困难一些。
事实证明,这是一个非常好的主意,它简单直接! 我照你说的把这行添加到了Global.asax.cs中: ViewEngines.Engines.Add(new WingBeats.Mvc.WingBeatsTemplateEngine()); 谢谢! (即使我挣扎了好几个小时,我也觉得有点愚蠢,不能自己想出这个解决方案!) –
2010-07-05 21:22:22