为什么这"对于类型测试模式"失败?

时间:2015-11-07 17:17:55

标签: f# type-conversion pattern-matching

我目前从类型中提取有关方法的信息是我当前代码的相关部分(正常工作):

let ctorFlags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.Static
let methodFlags = BindingFlags.DeclaredOnly ||| ctorFlags

[
    for t in Assembly.GetExecutingAssembly().GetTypes() do
        for c in t.GetConstructors ctorFlags -> c :> MethodBase
        for m in t.GetMethods methodFlags -> m :> MethodBase
]
|> printfn "%A"

然后我想使用syntaxfor pattern in expr的事实做一个小改动。如果给定的输入与给定类型的(或派生类型)匹配,则type test pattern匹配;所以我写了这个:

// same flags as before
[
    for t in Assembly.GetExecutingAssembly().GetTypes() do
        for :? MethodBase as m in t.GetConstructors ctorFlags -> m
        for :? MethodBase as m in t.GetMethods methodFlags -> m
]
|> printfn "%A"

这让我在GetConstructors行(由我翻译成英文)

时出错
  

类型约束不兼容。类型MethodBaseConstructorInfo类型不兼容。

经过仔细检查ConstructorInfo派生自MethodBase(同样适用于MethodInfo)。

注意:如果我使用灵活类型(#MethodBase)代替;模式有效,但构造函数m的类型为RuntimeConstructorInfo,方法m的类型为RuntimeMethodInfo(使用灵活类型的预期行为是什么)。我显然是单独测试它们,因为不允许列出两种不同的类型。

所以问题是:为什么我错过/误解了?

1 个答案:

答案 0 :(得分:3)

当您尝试使用:?模式从子类型( upcast )转换为超类型时,编译器会报告错误,该子类型是一个永远不会失败的转换。值得注意的是,当您在其他任何地方使用:?模式进行向上播放时,您会得到完全相同的错误:

match System.Random() with
| :? obj as o -> o

我认为:?模式主要用于安全向下转换(模式匹配失败时的情况)。例如:

match box 1 with
| :? string as s -> "string"
| :? int as n -> "int"

编译器会检查您要转换为的类型(此处为stringint)是否为参数中使用的类型的有效子类型(此处为object)。

string转换为object(或ConstructorInfo转换为MethodBase)也是有效的,但出于不同的原因 - 编译器显然只是更常见的类型检查。

您尝试使用:?对我来说绝对有意义 - 我认为编译器中的检查可以放宽以允许这样做。你可以post this as a suggestion to the F# user voice