F#类型约束和反射

时间:2013-01-15 00:50:29

标签: f#

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

我怀疑没有,因为表达式

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

似乎没有错误。不过,我想听听一些权威的意见。

1 个答案:

答案 0 :(得分:6)

引用Don Syme的全面post on equality and comparison constraints

约束类型:比较在以下情况下成立:

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

约束'T when 'T :> IComparable可以在CIL中编码并反映,但'T when 'T : comparison都不是。

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

equality约束与IEquatable<_>之间存在类似的关系。

修改

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