如何在FSharp编译器服务中检查一个类型是否为Option


let foo = None

在上面的例子中,在FSharp或FSharp编译器服务中是否有一种方法可以确定foo是否是Option类型,而无需进行反射?

我尝试了以下函数,但在访问下面代码中的fsharpType.TypeDefinition.FullName属性时出现System.InvalidOperationException: 'the type 'obj' does not have a qualified name'错误。

let private isOptionType (fsharpType:FSharpType) =    
if fsharpType.HasTypeDefinition then    
let fullnme = fsharpType.TypeDefinition.FullName
match fsharpType.TypeDefinition.TryFullName with
| Some fullName -> (Type.GetType fullName).GetGenericTypeDefinition() = typedefof<Option<_>>
| None -> false
else
false
let private checkOptionType (checkFile:FSharpCheckFileResults) = fun () ->   
let partialAssemblySignature = checkFile.PartialAssemblySignature    
let moduleEntity = partialAssemblySignature.Entities.[0]
let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
isOptionType fnVal.FullType

我不知道F#编译器服务所理解的F#option类型为什么没有限定名称,但我可以确认,当我尝试执行此操作时,我也遇到了同样的错误。

也就是说,我认为您可以重新考虑如何检测一个类型是否为option。您的方法是获取一个完全限定的名称,然后查看它是否与运行编译器服务的F#库中的option的名称匹配。我想这是可行的,但同样,您可以将名称检查为字符串:

let isOptionType (fsharpType:FSharpType) =    
fsharpType.HasTypeDefinition &&
fsharpType.TypeDefinition.Namespace = Some "Microsoft.FSharp.Core" &&
fsharpType.TypeDefinition.CompiledName = "option`1"

如果你想要更健壮的东西,那么我认为最好的选择是使用F#编译器服务来键入只使用"let x = None"的最小代码片段,提取x变量的类型,保存它,然后,当你需要检查其他东西是否是选项类型时,将其类型定义与x类型的类型定义进行比较。

作为参考,我从F#编译器服务文档中获取了代码示例,并添加了以下内容:

let file = "/home/user/Test.fsx"
let input = "let x = None"
let parseFileResults, checkFileResults = 
parseAndTypeCheckSingleFile(file, SourceText.ofString input)
let partialAssemblySignature =  
checkFileResults.PartialAssemblySignature
let typ = 
partialAssemblySignature.Entities.[0].
MembersFunctionsAndValues.[0].FullType
isOptionType typ // Returns 'true'

最新更新