F # equivalente del C # typeof (IEnumerable <>)
-
21-09-2019 - |
Domanda
Ho un pezzo di codice in cui ho bisogno di capire se un determinato tipo implementa IEnumerable<T>
(non mi interessa circa il T)
Ho provato (t:System.Type
nel caso in cui ti chiedi)
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<>>
)
, tuttavia, che non verrà compilato (la compilazione non piace il <>). Allora ho provato
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<'a>>
)
, ma ottenere un avvertimento che 'un vincolo è a obj. Non voglio per capire se IEnumerable<obj>
è implementato, ma IEnumerabl<>
.
Uno sa è la soluzione e btw sentitevi liberi di commentare il codice di cui sopra pure.
Soluzione
Questo dovrebbe funzionare:
typedefof<System.IEnumerable<_>>
Modifica
Come osserva Tomas, non c'è niente di speciale il carattere jolly _
qui; F # deduce che il tipo di obj
è il tipo più generale applicabile in questo contesto, quindi questo è lo stesso che utilizza typedefof<System.IEnumerable<obj>>
. In alcuni casi il modo in cui funziona può essere un po 'un ostacolo, però. Per esempio, se si definisce un type I<'a when 'a :> I<'a>> = interface end
interfaccia, quindi non è possibile utilizzare typedefof<I<_>>
, perché I<obj>
non soddisfa il vincolo generico e F # non può dedurre un altro tipo più appropriato. Questo può accadere anche senza vincoli ricorsivi (ad esempio type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end
. Questo è in contrasto con l'approccio C # s ', che funziona perfettamente bene nei casi analoghi.
Per quanto riguarda il codice stesso, penso che ti consigliamo di fare alcune altre modifiche, anche, come garantire che l'interfaccia è generico prima di chiamare GetGenericTypeDefinition
. Ecco come mi piacerebbe scrivere la funzione di test:
(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))
Altri suggerimenti
Per quanto ne so, F # non ha alcun equivalente a typeof(IEnumerable<>)
C # 's. Questo perché, si tratta di una sintassi speciale sostenuto esplicitamente da C #. In F #, typeof
è una funzione normale e l'argomento di tipo deve essere un tipo completamente specificato. È possibile ottenere una definizione di tipo generico programatically in questo modo:
let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()
Il problema con la soluzione con IEnumerable<'a>
è che il compilatore F # ha ancora bisogno di trovare qualche tipo concreto da utilizzare (come definizione di tipo generico non è un tipo valido). Se il tipo di inferenza deduce che il parametro di tipo non è limitata in alcun modo, utilizza tipo di default, che è obj
.
Modifica non sapevo di typedefof<IEnumerable<_>>
, che è molto utile! In ogni caso, notare che la sottolineatura non ha alcun significato speciale qui - l'argomento vero e proprio tipo è ancora IEnumerable<obj>
, ma la funzione typedefof
chiamate GetGenericTypeDefinition
dietro la scena
Sarei negligente per non sottolineare che questa domanda è uno dei tanti cui risposte si trovano in