从静态成员访问let bound字段

时间:2010-06-23 04:31:34

标签: f#

有没有办法从静态成员访问let bound字段?以下给出了指示的错误:

type Foo(x) =
    let x = x
    static member test() =
        let foo = Foo(System.DateTime.Now.Month)
        printfn "%A" foo.x //the field, constructor or member 'x' is not defined
        ()

私有显式字段允许从静态成员访问:

type Bar =
    val private x:int
    new(x) = { x=x }
    static member test() =
        let Bar = Bar(System.DateTime.Now.Month)
        printfn "%A" Bar.x
        ()

文档http://msdn.microsoft.com/en-us/library/dd469494.aspx指出“显式字段不适合日常使用”,但从静态成员访问私有实例字段肯定是例行情况。此外,我不相信您可以在主构造函数中设置显式字段,这意味着如果需要从静态成员访问一个私有实例字段,则必须将所有字段移动到显式字段,并且您不能再使用主要构造函数 - 它是全部或全部。

作为您真正希望从静态成员访问私有实例字段的真实示例,请考虑一个大整数实现:BigInteger类将是不可变的,因此大整数的内部表示将保留为私有实例字段(我们称之为data)。现在,假设您认为Add(other)实例方法不适合不可变数据结构,并且您只想实现静态Add(lhs,rhs)方法:在这种情况下,您需要能够访问{{1 }和lhs.data

2 个答案:

答案 0 :(得分:7)

我认为你不能这样做......事实上,你不能从其他实例访问let-bound值:

type Foo() =
  let x = 3
  member this.Test(f:Foo) =
    f.x // same error

通常,如果您需要从它所属的实例外部访问这样的值,您应该创建一个私有属性来获取值,或者使用私有字段。

<强>更新 这由section 8.6.2 of the spec涵盖。特别是:

  

实例“let”绑定在词法范围内(因此隐式私有)绑定到正在定义的对象。

也许来自F#团队的人会对这种语言行为方式的确切答案进行权衡。但是,我可以想到几个潜在的原因:

  1. let-bound值甚至可能不作为字段出现(例如,再次来自规范,let绑定将由构造函数的local表示)如果值不是语法函数,则不可变并且不使用在任何职能或成员“)
  2. 这似乎与该语言中其他地方的绑定行为一致。请参阅我进一步包含的大致等效的类和记录定义的示例(因为我似乎无法在有序列表中正确格式化代码块...)
  3. 这提供了比许多其他语言更精细的封装级别 - 绑定对于定义的对象是本地的。通常,其他实例不需要访问这些绑定,在这种情况下,最好不要公开它们。
  4. 如果你想要你的类的其他实例(或静态方法)可以访问的东西,有一种简单的方法可以做到这一点 - 创建一个私有字段或属性,这有利于明确表达你的意图值可以从您所在实例的外部访问。
  5. 如前所述,这里有一个大致相同的类定义和创建记录的方法:

    type MyClass(i:int) =
      let j = i * i
      member this.IsSameAs(other:MyClass) = 
        false // can't access other.j here
    
    type myRecord = { isSameAs : myRecord -> bool }
    let makeMyRecord(i:int) =
      let j = i * i
      { isSameAs = (fun r -> false) } //obviously, no way to access r.j here
    

    由于F#中的构造函数在概念上类似于返回类型实例的任何其他函数(例如,可以在不使用new的情况下调用它们),因此调用MyClass 5在概念上类似于调用{{1 }}。在后一种情况下,我们显然不希望有任何方法可以从记录的另一个实例访问makeMyRecord 5的本地let绑定。因此,在前一种情况下,我们也无法访问绑定。

答案 1 :(得分:0)

  

然后,访问来自的绑定字段   静态成员肯定是例行公事   方案

你在这里是什么意思?什么是相应的C#场景(有一个例子)?

请注意,这是合法的:

type Foo() =
    let x = 4
    member this.Blah = x + 1
    member private this.X = x
    static member Test(foo:Foo) =
        foo.X

也就是说,您可以将let-bound值公开为私有成员,静态可以读取/使用它。