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

C# 如何在调用构造函数之前初始化F#中的字段?,c#,.net,function,f#,delegates,C#,.net,Function,F#,Delegates,此代码无法正常工作,因为从基本构造函数调用了getEntriesChangedBServable,而FMyEntries为null,因为尚未调用它自己的构造函数 type MyEnumDefinition () = inherit DynamicEnumDefinitionBase<MyEnumDefinition> () let FMyEntries : ObservableCollection<string> = ObservableCollect

此代码无法正常工作,因为从基本构造函数调用了
getEntriesChangedBServable
,而
FMyEntries
null
,因为尚未调用它自己的构造函数

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
编辑: 简短的回答,这是不可能的!即使在应用Fyodor Soikin建议的hack时,F#runtime也会检查初始化过程,如果构造函数试图访问任何成员(如果它自己的实例)就会抛出异常


最后,我通过添加一个Initialize()函数解决了这个问题,该函数的作用与构造函数相同。

通常,在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 }
类型[]MyEnumDefinition()=
继承DynamicEnumDefinitionBase()
抽象成员GetMyEntries:unit->ObservableCollection
重写此=
可观察。FromEventPattern(
(fun h->this.GetMyEntries().CollectionChanged.AddHandler h),
(fun h->this.GetMyEntries().CollectionChanged.RemoveHandler h)))
设mkMyEnumDefinition()=
设MyEntries=ObservableCollection()
{new MyEnumDefinition(),带覆盖_uu.GetMyEntries()=MyEntries}
注意
通常,您可以直接创建基类(即
{new dynamiceneumdefinitionbase with…}
),但在这种情况下,您必须有一个派生类作为泛型参数提供。另一种设计气味。

在您发现
FMyEntries
为null的点上,调用堆栈是什么?好的点,在错误的轨道上。我已经编辑了这个问题。这看起来很天才,但不幸的是在我的例子中不起作用,因为基类将是一个singleton,并用子类的主构造函数构造singleton实例,这就是为什么它需要子类作为泛型参数,并对其具有new()约束。你能想出一个带有GetMyEntries函数的解决方案,该函数在访问时检查FMyEntries,如果它为null,则初始化它吗?我目前的方法是:唯一的问题是,两个do语句不再像这样工作了……不,不是F#从构造函数检查成员访问并抛出“对象或值的初始化导致对象或值在完全初始化之前被递归访问。”异常…因此我将进一步尝试抽象类和主构造函数,似乎没有任何帮助,此异常不会消失。我最终引入了Initialize()方法,该方法在第一次访问singleton时被调用。
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 }