Вопрос

У меня есть фрагмент кода, где мне нужно выяснить, реализует ли данный тип IEnumerable<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>>
    )

но get - это предупреждение о том, что 'a - это ограничение для obj.Я не хочу выяснять, если IEnumerable<obj> реализован, но IEnumerabl<>.

Любой знает, что это за решение, и, кстати, не стесняйтесь также комментировать приведенный выше код.

Это было полезно?

Решение

Это должно сработать:

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.Это в отличие от подхода C #, который отлично работает в аналогичных случаях.

Что касается самого вашего кода, я думаю, вы захотите внести и некоторые другие изменения, например, убедиться, что интерфейс является универсальным перед вызовом GetGenericTypeDefinition.Вот как я бы написал тестовую функцию:

(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))

Другие советы

Насколько я знаю, F # не имеет никакого эквивалента C # 's typeof(IEnumerable<>).Это связано с тем, что это специальный синтаксис, явно поддерживаемый C #.В F#, typeof это обычная функция, и аргумент type должен быть полностью заданного типа.Вы можете получить общее определение типа программно следующим образом:

let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()

Проблема с вашим решением с IEnumerable<'a> заключается в том, что компилятору F # все еще необходимо найти какой-то конкретный тип для использования (поскольку определение универсального типа не является допустимым типом).Если вывод типа показывает, что параметр типа никоим образом не ограничен, он использует тип по умолчанию, который obj.

Редактировать Я не знал о typedefof<IEnumerable<_>>, это очень полезно!В любом случае, обратите внимание, что подчеркивание здесь не имеет никакого особого значения - фактический аргумент type по-прежнему IEnumerable<obj>, но тот typedefof вызовы функций GetGenericTypeDefinition за сценой.

Я был бы упущением, если бы не указал, что этот вопрос является одним из многих, ответы на которые можно найти в

Как выглядит этот код C # в F #?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top