【问题标题】:Why this "for type-test pattern" fails?为什么这种“用于类型测试模式”会失败?
【发布时间】:2016-02-08 16:54:59
【问题描述】:

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

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 (使用灵活类型的预期行为是什么)。我显然单独测试了它们,因为不允许列出两种不同类型的列表。

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

【问题讨论】:

  • 如果你使用 :> 而不是 ?>,这能解决你的问题吗?
  • @Foole 我不使用 ?> (甚至不确定它是否存在)如果你的意思是替换:?使用 :> 不能以某种模式完成,所以只有我可以使用 :> 的地方才会出现在 for 的“主体”中,而这正是我在初始代码中所做的。如果你不是那个意思,那我就不明白了。

标签: f# type-conversion pattern-matching


【解决方案1】:

当您尝试使用:? 模式从子类型(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

【讨论】:

  • 所以基本上这是文档中的错误,不是吗?它清楚地表明派生类型输入是一个匹配,它似乎是相反的:派生类型只允许用于情况而不是输入部分。
  • 我不同意最新的段落。 for :? MethodBase as m in t.GetConstructors ctorFlags -> m 真的应该是for m in t.GetConstructors ctorFlags -> m :> MethodBase;这些是不同的用例:前者可能不匹配列表中的所有元素,后者是由于 F# 没有隐式向上转换。 IMO 潜在过滤的语义应该与向上转换明确区分开来。
猜你喜欢
  • 1970-01-01
  • 2020-05-05
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多