如何在构造函数被调用之前初始化F#中的字段?
此代码无法正常工作,因为GetEntriesChangedObservable
由基础构造函数调用,FMyEntries
为null
,因为它自己的构造函数尚未调用。如何在构造函数被调用之前初始化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()函数来解决它。
通常情况下,在调用基构造函数之前,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 ... }
),但在这种情况下,你有有一个派生类为供应泛型参数。另一种设计气味。
这看起来很天才,但不幸的是在我的情况下不起作用,因为基类将是一个单例,并用子类的主构造函数构造单例实例,这就是为什么它需要子类作为泛型参数并具有new()约束它。你能想到一个带有GetMyEntries函数的解决方案,该函数检查FMyEntries的访问权限,如果它是空的,然后初始化它? – thalm
我目前的做法是在这里:https://pastebin.com/yTXw1CXX唯一的问题是,这两个做语句不能像这样工作... – thalm
Nah,没有工作,因为F#检查构造函数的成员访问和抛出一个“对象或值的初始化导致对象或值在其完全初始化之前递归访问”。异常...所以我会尝试进一步抽象类和主要构造函数 – thalm
在找到'FMyEntries'为空的地方,调用堆栈是什么? –
好点,是在错误的轨道上。我编辑了这个问题。 – thalm