不幸的是,沒有辦法很好地做到這一點。如果您可以控制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