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.

Foi útil?

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

Como é esse código C# em f#?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top