К сожалению, нет никакого способа сделать это красиво. Если у вас есть контроль над типом 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 (новый WingBeats.Mvc.WingBeatsTemplateEngine()); Спасибо! (Я чувствую себя немного глупо, чтобы не придумать это решение самостоятельно, хотя я боролся часами!) –