2015-11-07 86 views
1

我目前正在提取有关从这里型方法的信息是我当前的代码的相关部分(其中正常工作):为什么这个“对于类型测试模式”失败?

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线(由我翻译成英文)

不兼容的类型约束。类型MethodBase与类型ConstructorInfo不兼容。

经过仔细检查ConstructorInfo源自MethodBase(并且与MethodInfo相同)。

注意:如果使用柔性类型(#MethodBase)代替;该模式的工作原理,但对构造m的类型为RuntimeConstructorInfo和方法m散列类型RuntimeMethodInfo(什么是使用灵活型预期的行为)。我明显地测试了它们,因为有两种不同类型的列表是不允许的。

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

+0

如果你使用:中>代替>,这是否解决您的问题? – Foole

+0

@Fole我不使用?>(甚至不知道它存在),以防万一你的意思是替换:?与:>不能在一个模式中完成,所以只有我可以使用的地方:>将在for的“body”中,这正是我在最初的代码中完成的。如果你不是那个意思,那我就不明白了。 – Sehnsucht

回答

3

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

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

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

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

编译器检查你铸造(这里stringint)类型是在参数(这里object)所使用的类型的有效子类型。

转换stringobject(或ConstructorInfoMethodBase)也将是有效的,但出于不同的原因 - 和编译器显然不仅会较为常见的一种检查。

您尝试使用:?绝对会让很多的意义,我 - 我认为在编译器检查可以放宽,允许这一点。你可以post this as a suggestion to the F# user voice

+0

所以基本上这是文档中的错误,不是吗?它清楚地表明,派生类型输入在匹配的地方看起来是相反的:派生类型只允许用于不是输入部分的情况。 – Sehnsucht

+0

我不同意最新的段落。 '为:? MethodBase as m in t.GetConstructors ctorFlags - > m' should be'for m in t.GetConstructors ctorFlags - > m:> MethodBase';这些是不同的用例:前者可能不匹配列表中的所有元素,后者是由于F#没有隐式的upcasts。国际海事组织的潜在过滤语义应该与上传清楚地分开。 – CaringDev