鉴于以下情况:
let f<'a,'b> = typeof<'a>.Name, typeof<'b>.Name //val f<'a,'b> : string * string
let g<'a,'b>() = typeof<'a>.Name, typeof<'b>.Name //val g<'a,'b> : unit -> string * string
以下引文产生了看似相同Expr
的 s:
let fq = <@ f<int,string> @> //Call (None, System.Tuple`2[System.String,System.String] f[Int32,String](), [])
let gq = <@ g<int,string>() @> //Call (None, System.Tuple`2[System.String,System.String] g[Int32,String](), [])
使用调试器进行挖掘,我看不出有任何方法可以判断这f
是一个泛型值,而g
它是一个泛型函数:是否可以仅从fq
and来判断它gq
?由于 F# 可以区分程序集之间f
和g
程序集之间的差异,我认为我很有可能能够从引用中获取元数据。虽然一个问题可能是 F# 似乎实际上编译了f
一个函数版本unit -> string * string
(查看反汇编代码;可能是为了与其他 .NET 语言互操作),所以如果引用使用的是函数版本,则信息可能会丢失.
更新
根据@Tomas 的指导,这是我想出的:
let isGenericValue (mi:MemberInfo) =
try
let mOrV =
FSharpEntity.FromType(mi.DeclaringType).MembersOrValues
|> Seq.find (fun mOrV -> mOrV.CompiledName = mi.Name)
not mOrV.Type.IsFunction
with
| :? System.NotSupportedException -> true //for dynamic assemblies, just assume idiomatic generic value
这可以用于匹配 on Patterns.Call(_,mi,_)
,其中第二个参数mi
是一个MemberInfo
实例。但是,有一个问题:它不适用于动态程序集(如 FSI)。