2010-06-23 39 views
8

有什麼辦法從靜態成員訪問允許綁定的字段?下面給出指示錯誤:從靜態成員訪問允許綁定的字段

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)方法:在這種情況下,您需要能夠訪問lhs.datarhs.data

回答

6

我不認爲你可以做到這一點......其實,你不能從其他實例或者訪問我們綁定值:

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

一般來說,如果你需要訪問這樣的值來自它所屬的實例之外,你應該創建一個私有屬性來獲取值或使用私有字段。

UPDATE 這涵蓋了section 8.6.2 of the spec。特別是:

Instance 「let」 bindings are lexically scoped (and thus implicitly private) to the object being defined.

也許有人來自F#團隊將權衡一個明確的答案,爲什麼語言的行爲如此。但是,我可以想到幾個潛在的原因:

  1. let-bound值可能不會作爲字段存在(例如,再次來自規範,let綁定將由本地構造函數表示「if該值不是語法功能,不可變,並且不用於任何函數或成員「)
  2. 這似乎與let語言中其他地方的綁定行爲一致。查看我已經進一步包含的大致相等的類和記錄定義的示例(因爲我似乎無法在有序列表中正確地格式化代碼塊......)
  3. 這提供了更細粒度的封裝級別比許多其他語言中可能的 - 對所定義的對象是局部的綁定。通常,其他實例不需要訪問這些綁定,在這種情況下,最好不要暴露它們。
  4. 如果你想要一些可以被你的類的其他實例(或者在靜態方法中)訪問的東西,有一種簡單的方法可以做到這一點 - 創建一個私有字段或屬性,這有利於明確表達你的意圖,值可以從你所在的實例之外訪問。

如前所述,這裏有一個大致相當於類定義和方法以創建一個記錄:

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在概念上類似於調用makeMyRecord 5。在後一種情況下,我們顯然不希望有任何方式從記錄的另一個實例訪問本地允許綁定j。因此,在前一種情況下,我們也無法獲得綁定的一致性。

+0

是否有任何技術或邏輯的原因,爲什麼讓綁定字段在這方面明確的私人領域應該有任何不同的行爲? – 2010-06-23 04:50:33

+1

@Stephen - 請參閱我的最新推測,瞭解爲什麼可能採取了這種方法。 – kvb 2010-06-23 05:27:57

+0

謝謝。他們在詞彙範圍的事實是否限制了編譯器發現它們作爲這些場景中的字段的能力(是否「隱含私有」=隱藏)? – 2010-06-23 12:50:26

0

yet, accessing let bound fields from static members is certainly a routine scenario

這是什麼意思?什麼是相應的C#場景(舉例)?

注意,這是合法的:

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

也就是說,你可以露出鬆懈綁定值作爲一個私有成員,它的靜態可以讀/使用。

+0

那麼,我真正的意思是訪問私有實例字段/成員/等。來自同一類的靜態成員的類是大多數oo編程語言所允許的常見場景......即使是F#,當你使用明確的「val」私有實例字段時,你也可以這樣做。我的意見是,我期望主要的構造函數/讓綁定語法就是這樣:當綁定字段被編譯爲字段時,我希望他們可以通過與普通私有字段相同的規則訪問。 – 2010-06-23 17:01:32

+0

我看到了 - 請參閱我的編輯。 – Brian 2010-06-23 17:09:41

+0

謝謝,我正在考慮採取這種方法,但我與它的主要問題是,我相信X是財產,而不是一個領域(我真的寧願使用一個領域)。 – 2010-06-23 17:18:17