F#类型约束和反射

eir*_*rik 3 f#

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

我怀疑不会,因为表达

typedefof<Set<_>>.MakeGenericType [| typeof<System.Type> |]
Run Code Online (Sandbox Code Playgroud)

似乎没有错误.不过,我想听听一些有关这方面的权威意见.

Dan*_*iel 6

引自Don Syme 关于平等和比较约束的全面帖子:

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

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

约束'T when 'T :> IComparable可以用CIL编码并反映在其上,而两者都不是'T when 'T : comparison.

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

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

编辑

杰克提到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))
Run Code Online (Sandbox Code Playgroud)

这是一个人为的例子,展示了实施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
Run Code Online (Sandbox Code Playgroud)