F# equivalente do C# typeof (iEnumerable <>)
-
21-09-2019 - |
Pergunta
Eu tenho um pedaço de código onde preciso descobrir se um determinado tipo implementa IEnumerable<T>
(Eu não me importo com o T)
Eu tentei (t:System.Type
Caso você se pergunte)
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<>>
)
No entanto, isso não vai compilar (a compilação não gosta do <>). Eu então tentei
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<'a>>
)
Mas Get é um aviso de que 'a é restrição para obj. Eu não quero descobrir se IEnumerable<obj>
é implementado, mas IEnumerabl<>
.
Qualquer um sabe a solução e, btw, sinta -se à vontade para comentar o código acima também.
Solução
Isso deve funcionar:
typedefof<System.IEnumerable<_>>
EDITAR
Como observa Tomas, não há nada de especial no _
curinga aqui; F# infere esse tipo obj
é o tipo mais geral aplicável nesse contexto, então é o mesmo que usar typedefof<System.IEnumerable<obj>>
. Em alguns casos, a maneira como isso funciona pode ser um pouco de obstáculo. Por exemplo, se você definir uma interface type I<'a when 'a :> I<'a>> = interface end
, então você não pode usar typedefof<I<_>>
, Porque I<obj>
Não satisfaz a restrição genérica e F# não pode inferir outro tipo mais apropriado. Isso pode acontecer mesmo sem restrições recursivas (por exemplo type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end
. Isso contrasta com a abordagem de C#, que funciona perfeitamente bem nos casos análogos.
Quanto ao seu código em si, acho que você também vai querer fazer outras mudanças, como garantir que a interface seja genérica antes de ligar GetGenericTypeDefinition
. Veja como eu escreveria a função de teste:
(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))
Outras dicas
Até onde eu sei, F# não tem nenhum equivalente a C# 's typeof(IEnumerable<>)
. Isso ocorre porque, esta é uma sintaxe especial suportada explicitamente por C#. Em f#, typeof
é uma função normal e o argumento do tipo precisa ser um tipo totalmente especificado. Você pode obter uma definição de tipo genérico programaticamente assim:
let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()
O problema com sua solução com IEnumerable<'a>
é que o compilador F# ainda precisa encontrar algum tipo de concreto para usar (como a definição de tipo genérico não é um tipo válido). Se o tipo de inferência deduzir que o parâmetro de tipo não é restrito de forma alguma, ele usa o tipo padrão, o que é obj
.
EDITAR Eu não sabia sobre typedefof<IEnumerable<_>>
, isso é muito útil! De qualquer forma, observe que o sublinhado não tem nenhum significado especial aqui - o argumento do tipo real ainda é IEnumerable<obj>
, mas o typedefof
chamadas de função GetGenericTypeDefinition
por trás da cena.
Eu seria negligente em não ressaltar que essa pergunta é uma das muitas cujas respostas são encontradas em