web-dev-qa-db-ja.com

C#typeof(IEnumerable <>)と同等のF#

特定の型が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>>
    )

しかし、 'aがobjへの制約であるという警告が表示されます。 IEnumerable<obj>が実装されているかどうかはわかりませんが、IEnumerabl<>です。

誰もが解決策を知っているので、上記のコードについてもコメントしてください。

40
Rune FS

これは機能するはずです:

typedefof<System.IEnumerable<_>>

[〜#〜]編集[〜#〜]

Tomasが指摘しているように、ここでは_ワイルドカードについて特別なことは何もありません。 F#は、タイプobjがこのコンテキストで最も一般的に適用可能なタイプであると推測するため、これはtypedefof<System.IEnumerable<obj>>を使用する場合と同じです。ただし、場合によっては、これが機能する方法が少し妨げになることがあります。たとえば、インターフェイスtype I<'a when 'a :> I<'a>> = interface endを定義した場合、typedefof<I<_>>は一般的な制約を満たさず、F#は別のより適切な型を推測できないため、I<obj>を使用できません。これは、再帰的な制約がなくても発生する可能性があります(例:type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end。これは、類似のケースで完全に正常に機能するC#のアプローチとは対照的です。

コード自体に関しては、GetGenericTypeDefinitionを呼び出す前にインターフェイスが汎用であることを確認するなど、他の変更も行う必要があると思います。テスト関数の記述方法は次のとおりです。

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

私の知る限り、F#にはC#のtypeof(IEnumerable<>)に相当するものはありません。これは、これがC#で明示的にサポートされている特別な構文であるためです。 F#では、typeofは通常の関数であり、type引数は完全に指定された型である必要があります。次のようにプログラムでジェネリック型定義を取得できます。

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

IEnumerable<'a>を使用したソリューションの問題は、F#コンパイラが使用する具体的な型を見つける必要があることです(ジェネリック型の定義は有効な型ではないため)。型推論により、型パラメーターがまったく制限されていないと推測される場合は、デフォルトの型であるobjが使用されます。

[〜#〜] edit [〜#〜]typedefof<IEnumerable<_>>について知りませんでした。とても便利です!とにかく、ここではアンダースコアに特別な意味はないことに注意してください。実際の型引数はIEnumerable<obj>のままですが、typedefof関数はバックグラウンドでGetGenericTypeDefinitionを呼び出します。

22
Tomas Petricek

この質問は、その答えがにある多くの質問の1つであることを指摘しないでください。

このC#コードはF#ではどのように見えますか?

6
Brian