【问题标题】:F# type constraints and reflectionF# 类型约束和反射
【发布时间】:2012-12-29 01:30:23
【问题描述】:

有没有办法通过反射来判断给定的类型参数是否满足F#比较约束?

我怀疑不是,因为表达式

typedefof<Set<_>>.MakeGenericType [| typeof<System.Type> |]

似乎没有产生任何错误。不过,我还是想听听一些权威的意见。

【问题讨论】:

  • 比较约束不是刚刚按照IComparable实现的吗?即,您不能只查看该类型是否实现了该接口吗?
  • 即使泛型参数确实实现了IComparable,也不一定意味着这是由约束强制执行的。换句话说,这必须在泛型参数约束中声明,但情况似乎并非如此。
  • @eirik 你是对的——如果你用 Reflector 查看 FSharpSet 类型的定义,对泛型参数类型没有任何约束(应该有一个约束,它实现 IComparable)。请通过microsoft.comfsbugs 报告此问题——这似乎是一个F# 编译器错误。
  • @JackP。这是一个怎样的错误?规范是否要求comparable 类型用'T :&gt; IComparable 标记?
  • @ildjarn 没那么简单。见blogs.msdn.com/b/dsyme/archive/2009/11/08/…

标签: f#


【解决方案1】:

引用 Don Syme 的彻底 post on equality and comparison constraints

约束 type : comparison 在以下情况下成立:

  • 如果类型是命名类型,则类型定义没有NoComparison 属性;和
  • 类型定义实现System.IComparable;和
  • 任何类型的“比较依赖”也满足tyi:比较

约束 'T when 'T :&gt; IComparable 可以在 CIL 中编码并反映,而 'T when 'T : comparison 两者都不是。

由于这两个约束不等价,将 comparable 类型标记为 IComparable 约束有点误导,因为使用反射无法区分两者。

equality 约束和IEquatable&lt;_&gt; 之间存在类似的关系。

编辑

Jack 提到 comparison 约束可以在 F# 元数据中编码,这促使我查看了 PowerPack 中的元数据阅读器。可用于检测约束:

open Microsoft.FSharp.Metadata

let setEntity = FSharpAssembly.FSharpLibrary.GetEntity("Microsoft.FSharp.Collections.FSharpSet`1")
for typeArg in setEntity.GenericParameters do
  printfn "%s - comparison=%b" 
    typeArg.Name 
    (typeArg.Constraints |> Seq.exists (fun c -> c.IsComparisonConstraint))

这是一个人为的例子,显示了实现IComparable 和满足comparison 之间的差异:

type A() = 
  interface IComparable with
    member __.CompareTo(_) = 0

[<NoComparison>]
type B() =
  inherit A()

type C<'T when 'T : comparison>() = class end
type D<'T when 'T :> IComparable>() = class end

let c = C<B>() //ERROR
let d = D<B>() //OK

【讨论】:

  • comparable 约束意味着IComparable,但不是相反(因为关于“比较依赖项”的额外限制,我想这是为了支持结构比较)。所以我认为 F# 编译器将IComparable(甚至IComparable&lt;T&gt;)约束添加到泛型参数中仍然是有意义的;不这样做会使与其他 CLR 语言的互操作容易出错——您始终必须确保自己添加这些约束。并且,如有必要,您可以在 F# 元数据资源中编码 comparison 约束。
  • @JackP。我认为你已经把它弄反了。实现IComparable 意味着一个类型满足comparable 约束,但不是相反(...)。
  • 我看不出它如何使与其他语言的互操作容易出错。错误会是什么?我不认为规范保证'T : comparison'T :&gt; IComparable 可以互换。
  • @Daniel -- 不是吗?您引用的规范的第二行说,对于支持comparison 约束的类型,它还必须实现IComparable。从某种意义上说,comparison :&gt; IComparable。第三行只是为了支持 F# 结构相等——你能想到任何需要通用参数来支持特定条件的情况,而不仅仅是IComparable?我不能——所以我认为将comparison 约束添加到F# 元数据中并在CIL 元数据中编码IComparable 约束是有意义的。
  • @JackP。我同意。我没有理由不添加它。我唯一的争论是称其为错误……也许是一个不错的功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多