F # эквивалент С# typeof (IEnumerable <>)
У меня есть фрагмент кода, где мне нужно выяснить, реализует ли данный тип IEnumerable<T>
(я не забочусь о T)
Я пробовал (t:System.Type
в случае, если вы задаетесь вопросом)
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<>>
)
однако это не будет компилироваться (компиляция не нравится < > ). Затем я попробовал
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<'a>>
)
но получите предупреждение, что 'a является ограничением на obj. Я не хочу выяснять, реализована ли IEnumerable<obj>
, но IEnumerabl<>
.
Любой знает решение, и btw не стесняйтесь комментировать код выше.
Ответы
Ответ 1
Это должно работать:
typedefof<System.IEnumerable<_>>
ИЗМЕНИТЬ
Как отмечает Томаш, здесь нет ничего особенного в шаблоне _
; F # указывает, что тип obj
является наиболее общим применимым типом в этом контексте, так что это то же самое, что и при использовании typedefof<System.IEnumerable<obj>>
. В некоторых случаях способ, которым это работает, может быть немного помехой. Например, если вы определяете интерфейс type I<'a when 'a :> I<'a>> = interface end
, то вы не можете использовать typedefof<I<_>>
, потому что I<obj>
не удовлетворяет общему ограничению, а F # не может вывести еще один подходящий тип. Это может произойти даже без рекурсивных ограничений (например, type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end
. Это контрастирует с подходом С#, который отлично работает в аналогичных случаях.
Что касается самого кода, я думаю, вам также захочется внести некоторые другие изменения, например, чтобы общий интерфейс был до вызова GetGenericTypeDefinition
. Вот как я бы написал тестовую функцию:
(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))
Ответ 2
Насколько я знаю, F # не имеет эквивалента С# typeof(IEnumerable<>)
. Это потому, что это специальный синтаксис, явно поддерживаемый С#. В F #, typeof
- нормальная функция, и аргумент типа должен быть полностью определенным типом. Вы можете получить типичное определение типа следующим образом:
let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()
Проблема с вашим решением с IEnumerable<'a>
заключается в том, что компилятору F # все еще нужно найти конкретный тип для использования (поскольку определение общего типа не является допустимым типом). Если вывод типа выводит, что параметр типа не ограничен каким-либо образом, он использует тип по умолчанию, который равен obj
.
EDIT Я не знал о typedefof<IEnumerable<_>>
, это очень полезно! В любом случае, обратите внимание, что подчеркивание здесь не имеет особого значения - фактический аргумент типа по-прежнему IEnumerable<obj>
, но функция typedefof
вызывает GetGenericTypeDefinition
за сценой.
Ответ 3
Я бы отказался не указывать, что этот вопрос является одним из многих, ответы которого найдены в
Что выглядит этот код С# в F #?