【问题标题】:F# operator "?"F# 运算符“?”
【发布时间】:2010-10-27 19:24:17
【问题描述】:

我刚刚阅读了this page 上的信息,而一个新的?提到了运营商,我不清楚它的用途是什么。
谁能提供一个快速的解释,发布一个如何使用这个运算符的代码,并可能提到一个用例?
编辑:这真的很尴尬,我注意到 ?操作员在 Don 的发行说明中不再提及。知道这是为什么吗?

【问题讨论】:

    标签: visual-studio-2010 f#


    【解决方案1】:

    在 nuget 上有一个模块 FSharp.Interop.Dynamic,它使用 dlr 实现动态运算符。

    let ex1 = ExpandoObject() in
    ex1?Test<-"Hi";
    ex1?Test |> should equal "Hi";
    

    它是开源的,Apache许可证,你可以看看implementation,它包括单元测试example cases

    【讨论】:

      【解决方案2】:

      在这个 F# 版本中有两个新的“特殊”运算符,(?) 和 (?

      a?b
      

      脱糖为:

      (?) a "b"
      

      和:

      a?b <- c
      

      脱糖为:

       (?<-) a "b" c
      

      这些运算符的一个非常简单的定义是:

      let inline (?) (obj: 'a) (propName: string) : 'b =
          let propInfo = typeof<'a>.GetProperty(propName)
          propInfo.GetValue(obj, null) :?> 'b
      
      let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
          let propInfo = typeof<'a>.GetProperty(propName)
          propInfo.SetValue(obj, value, null)
      

      请注意,由于 gettor 的返回类型是通用的,因此在大多数情况下,您必须在使用站点指定它,即:

      let name = foo?Name : string
      

      虽然你仍然可以链式调用 (?)(因为 (?) 的第一个参数也是通用的):

      let len = foo?Name?Length : int
      

      另一个更有趣的实现是重用VB提供的CallByName方法:

      open Microsoft.VisualBasic    
      
      let inline (?) (obj: 'a) (propName: string) : 'b =
          Interaction.CallByName(obj, propName, CallType.Get, null) :?> 'b //'
      
      let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
          Interaction.CallByName(obj, propName, CallType.Set, [| (value :> obj) |])
          |> ignore
      

      这样做的好处是它可以正确处理属性和字段,使用 IDispatch COM 对象等。

      【讨论】:

      • 附带说明,显然,F# PowerPack 包含一个合理的默认实现。
      【解决方案3】:

      听起来像“?”运算符与动态语言运行时 (DLR) 相关。也就是说,当您想在运行时而不是在编译时绑定到对象成员(方法、属性)时使用它。

      这很有趣,因为我希望这也是动态成员调用在 C# 中的工作方式。唉,C# 通过“伪”类型(“动态”IIRC)公开了这个功能。在我看来,这会使代码不太清晰(因为您必须跟踪变量声明才能知道调用是早期绑定还是后期绑定)。

      我不知道确切的语法,但如果我不得不猜测,它会替换或增加“。” (点)运算符。如:

      let x = foo?Bar()
      

      或者也许:

      let x = foo.?Bar()
      

      【讨论】:

      • “因为您必须跟踪变量声明以了解调用是提前绑定还是后期绑定”...您不必跟踪很远。 dynamic 必须是局部变量,不能是类型成员;如果您必须滚动很远才能确定变量是否是动态的,那么您可能需要重构。另外,如果您将鼠标悬停在变量名称上,IDE 会很乐意告诉您类型...
      • 好点。对于它的价值,我更喜欢“后期绑定调用”运算符而不是“动态”类型实现的另一个原因:鉴于可以通过实现接口连接到 DLR,我可以想象一个场景您想在同一个参考上进行早期绑定调用和后期绑定调用。
      • 出于好奇,foo 的类型应该是什么,为什么我要这样做而不是 foo.Bar()?此外,我不能通过反射获得相同的结果吗?
      • @emaster70 我怀疑引用的类型很重要。是的,在大多数情况下,您可以通过反射完成同样的事情,但是这样的代码很难编写,甚至更难阅读。此外,我认为 DLR 将支持反射不支持的场景。例如,我似乎想起了 C# 与 JavaScript 中定义的对象交互的 DLR 演示。
      猜你喜欢
      • 2010-11-30
      • 2015-10-15
      • 1970-01-01
      • 2017-12-10
      • 2011-02-18
      • 2019-01-19
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      相关资源
      最近更新 更多