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