F # эквивалент C # typeof (IEnumerable <>) - PullRequest
39 голосов
/ 19 марта 2010

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

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

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

Ответы [ 3 ]

54 голосов
/ 19 марта 2010

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

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>))
21 голосов
/ 19 марта 2010

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

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

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

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

6 голосов
/ 20 марта 2010

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

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

...