第七章 F# 库(二)

728 篇文章 1 订阅
86 篇文章 0 订阅

第七章 F# 库(二)

 

 

反射(Microsoft.FSharp.Reflection)模块

 

这个模块包含了 F# 自己的反射(reflection)版本。F#中的某些类型和通用语言运行时(CLR)的类型系统百分之百兼容,但是,它们并不能被 .NET反映准确理解。例如,F# 使用了某种技术实现了联合类型,这对纯 F#代码来说是的;当你使用 BCL 对它进行反射时,看起来有点奇怪,F#的反射系统解决了这种问题。但是,它和 BCL System.Reflection命名空间的混合,因此,如果你反映 F# 类型使用 BCL的类型,就会得到来自 System.Reflection 命名空间的适当类型。

F# 中,既可以反射,也可以反射值,差别有一点微妙,因此,最好的解释是用示例。熟悉 .NET反射的人可以把反射类型是使用 TypeEventInfoFieldInfoMethodInfo PropertyInfo 类型,而把反射值看做是调用它们的成员,比如,用 GetProperty InvokeMember动态获得值;然而,反射值提供了高级、易用的系统。

反射类型(Reflection over types):检查组成特定值或类型的类型;

反射值(Reflection over values):检查组成特定组合值(composite value)的值。

 

 

反射类型(Reflection over types

 

下面示例中函数能够打印任何元组的类型:

 

open Microsoft.FSharp.Reflection

 

let printTupleTypes (x: obj) =

  let t = x.GetType()

  if FSharpType.IsTuple t then

    types = FSharpType.GetTupleElements t

    printf "("

    types

    |> Seq.iteri

      (fun i t ->

      if i <> Seq.length types - 1 then

        printf " %s * " t.Name

      else

        printf "%s" t.Name)

    printfn " )"

  else

    printfn "not a tuple"

 

printTupleTypes ("hello world", 1)

 

首选,使用对象的 GetType 方法得到表示这个对象的类型(System.Type);然后,对这个值使用函数 FSharpType.IsTuple检查它是否是元组;接着,再使用函数 FSharpType.GetTupleElements得到一个类型(System.Type)数组,描述组成元组的元素。这些可以表示成 F#的类型,因此,能够递归地调用函数,检查它们的内容。这里,我们知道它们是 .NET BCL的类型,就简单地输出类型的名字,这样,示例运行的结果如下:

 

( String * Int32 )

 

 

反射值(Reflection over values

 

假设不想显示元组的类型,而是想显示组成元组的值,需要这样做:使用反射值,还需要使用函数 FSharpValue.GetTupleFields得到一个对象数组,这是组成这个元组的值。这些对象可能是元组,也可能是其他 F# 类型,因此,需要递归调用这个函数,去输出对象的值。然而,在这里,我们知道底层的值来自 BCL 的库,因此,只要简单地使用F# printfn函数来输出就行了,F# printf模块在本章的后面有讲解。下面的示例实现了这样一个函数:

 

open Microsoft.FSharp.Reflection

 

let printTupleValues (x: obj) =

  if FSharpType.IsTuple(x.GetType()) then

    let vals = FSharpValue.GetTupleFields x

    printf "("

    vals

    |> Seq.iteri

       (fun i v ->

         if i <> Seq.length vals - 1 then

           printf " %A, " v

         else

           printf " %A" v)

    printfn " )"

  else

    printfn "not a tuple"

 

printTupleValues ("hello world", 1)

 

代码的运行结果如下:

 

( "hello world", 1 )

 

反射既可以用于 fsi,它是 F#工具套件中的交互式命令行工具,也可以 F# 库函数 printf族。如果要学习更多有关反射的使用,可以看一看 printf 的源代码,在发布的  \source\fsharp\printf.fs \source\fsharp\layout.ml 中。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值