我目前从类型中提取有关方法的信息是我当前代码的相关部分(正常工作):
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"
然后我想使用syntax为for 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
行(由我翻译成英文)
类型约束不兼容。类型
MethodBase
与ConstructorInfo
类型不兼容。
经过仔细检查ConstructorInfo派生自MethodBase(同样适用于MethodInfo)。
注意:如果我使用灵活类型(#MethodBase
)代替;模式有效,但构造函数m
的类型为RuntimeConstructorInfo
,方法m
的类型为RuntimeMethodInfo
(使用灵活类型的预期行为是什么)。我显然是单独测试它们,因为不允许列出两种不同的类型。
所以问题是:为什么我错过/误解了?
答案 0 :(得分:3)
当您尝试使用:?
模式从子类型( upcast )转换为超类型时,编译器会报告错误,该子类型是一个永远不会失败的转换。值得注意的是,当您在其他任何地方使用:?
模式进行向上播放时,您会得到完全相同的错误:
match System.Random() with
| :? obj as o -> o
我认为:?
模式主要用于安全向下转换(模式匹配失败时的情况)。例如:
match box 1 with
| :? string as s -> "string"
| :? int as n -> "int"
编译器会检查您要转换为的类型(此处为string
和int
)是否为参数中使用的类型的有效子类型(此处为object
)。
将string
转换为object
(或ConstructorInfo
转换为MethodBase
)也是有效的,但出于不同的原因 - 编译器显然只是更常见的类型检查。
您尝试使用:?
对我来说绝对有意义 - 我认为编译器中的检查可以放宽以允许这样做。你可以post this as a suggestion to the F# user voice。