对F#度量单位的反思

Sae*_*iri 8 c# reflection f#

目前已在F#中添加了对反射的支持,但它不适用于度量类型.是否可以在F#中使用反射来测量类型?我读过这个.它是在2008年,但是如果你在ildasm中查看一些像bellow这样的代码你就看不出任何东西了Units of Measure.

// Learn more about F# at http://fsharp.net

[<Measure>] type m
[<Measure>] type cm

let CalculateVelocity(length:float<m> ,time:float<cm>) =
    length / time
Run Code Online (Sandbox Code Playgroud)

ildasm输出:

.method public static float64  CalculateVelocity(float64 length,
                                                 float64 time) cil managed
{
  // Code size       5 (0x5)
  .maxstack  4
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  div
  IL_0004:  ret
} // end of method Program::CalculateVelocity
Run Code Online (Sandbox Code Playgroud)

所以有些东西无法在F#中反映出来.这是真的吗?看到评论:CLR中的单位实际上根本没有被看到......在文章中.

Tom*_*cek 18

正如其他人已经指出的那样,当您需要获取有关已编译F#类型的一些信息时,您可以使用标准.NET反射(System.Reflection)和F#反射,它提供有关受歧视的联合,记录等的信息(Microsoft.FSharp.Reflection).

遗憾的是,无法使用这两个API中的任何一个访问有关度量单位的信息,因为它们仅在编译期间进行检查,并且在运行时实际上不存在(它们无法以任何方式在CLR中表示).这意味着您永远无法确定例如盒装浮点值是否具有某种度量单位...

您可以使用F#PowerPack中的命名空间获取有关度量单位的一些信息Metadata.例如,以下打印foo为单位:

namespace App
open System.Reflection
open Microsoft.FSharp.Metadata

[<Measure>] 
type foo

module Main = 
  let asm = FSharpAssembly.FromAssembly(Assembly.GetExecutingAssembly())
  for ent in asm.Entities do
    if ent.IsMeasure then
      printfn "%s is measure" ent.DisplayName
Run Code Online (Sandbox Code Playgroud)

这将读取编译器存储在编译文件中的一些二进制元数据(以便在引用其他F#库时可以看到单元),因此您应该能够看到有关F#库的公共API的信息.