К сожалению, нет способа сделать это красиво.Если у вас есть контроль над типом 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
- найти функцию с помощью отражения немного сложнее.