2017-08-08 35 views
2

此代碼無法正常工作,因爲GetEntriesChangedObservable由基礎構造函數調用,FMyEntriesnull,因爲它自己的構造函數尚未調用。如何在構造函數被調用之前初始化F#中的字段?

type MyEnumDefinition() = 
    inherit DynamicEnumDefinitionBase<MyEnumDefinition>() 

    let FMyEntries : ObservableCollection<string> = ObservableCollection<string>() 

    //gets called from base constructor 
    override this.GetEntriesChangedObservable() = 
     Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>( 
      (fun h -> FMyEntries.CollectionChanged.AddHandler h), //FMyEntries is null 
      (fun h -> FMyEntries.CollectionChanged.RemoveHandler h)) //FMyEntries is null 

應該如何FMyEntries進行初始化,使其具有任何構造函數之前的值被調用?

在C#中它應該是這樣的:

//initialized before constructor 
    ObservableCollection<string> FMyEntries = new ObservableCollection<string>(); 

    //gets called from base constructor 
    protected override IObservable<object> GetEntriesChangedObservable() 
    { 
     return Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
      h => FMyEntries.CollectionChanged += h, 
      h => FMyEntries.CollectionChanged -= h); 
    } 

編輯: 簡短的回答,這是不可能的!即使應用Fyodor Soikin提出的破解,F#運行時也會檢查初始化過程,並在構造函數嘗試訪問任何成員(如果它自己的實例)時引發異常。

我最終通過添加與構造函數相同的Initialize()函數來解決它。

+0

在找到'FMyEntries'爲空的地方,調用堆棧是什麼? –

+0

好點,是在錯誤的軌道上。我編輯了這個問題。 – thalm

回答

2

通常情況下,在調用基構造函數之前,F#中不可能初始化字段/屬性,因此您將無法創建這樣的類(這裏我必須注意:通常對於祖先構造函數來說,指望後代被初始化;我知道,小安慰)。

但有一個例外:在一個對象表達式中,封閉變量在基礎構造函數被調用之前被初始化。所以,你可以應用此略有醜陋的解決方法:

type [<AbstractClass>] MyEnumDefinition() = 
    inherit DynamicEnumDefinitionBase<MyEnumDefinition>() 

    abstract member GetMyEntries: unit -> ObservableCollection<string> 

    override this.GetEntriesChangedObservable() = 
     Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>( 
      (fun h -> this.GetMyEntries().CollectionChanged.AddHandler h), 
      (fun h -> this.GetMyEntries().CollectionChanged.RemoveHandler h))) 

let mkMyEnumDefinition() = 
    let MyEntries = ObservableCollection<string>() 
    { new MyEnumDefinition() with override __.GetMyEntries() = MyEntries } 

注意: 通常情況下,你可以直接創建基類(即{ new DynamicEnumDefinitionBase with ... }),但在這種情況下,你有一個派生類爲供應泛型參數。另一種設計氣味。

+0

這看起來很天才,但不幸的是在我的情況下不起作用,因爲基類將是一個單例,並用子類的主構造函數構造單例實例,這就是爲什麼它需要子類作爲泛型參數並具有new()約束它。你能想到一個帶有GetMyEntries函數的解決方案,該函數檢查FMyEntries的訪問權限,如果它是空的,然後初始化它? – thalm

+0

我目前的做法是在這裏:https://pastebin.com/yTXw1CXX唯一的問題是,這兩個做語句不能像這樣工作... – thalm

+0

Nah,沒有工作,因爲F#檢查構造函數的成員訪問和拋出一個「對象或值的初始化導致對象或值在其完全初始化之前遞歸訪問」。異常...所以我會嘗試進一步抽象類和主要構造函數 – thalm

相關問題