如何在调用构造函数之前初始化F#中的字段?

时间:2017-08-08 17:33:02

标签: c# .net function f# delegates

此代码无法正常运行,因为GetEntriesChangedObservable是从基础构造函数调用的,而FMyEntriesnull,因为它自己的构造函数不是{\ n}叫了。

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建议的hack,F#运行时也会检查初始化过程,如果构造函数尝试访问任何成员(例如它自己的实例),则抛出异常。

我最后通过添加一个与构造函数相同的Initialize()函数来解决它。

1 个答案:

答案 0 :(得分: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 ... }),但在这种情况下,要派生类作为通用参数提供。另一种设计气味。