此代码无法正常运行,因为GetEntriesChangedObservable
是从基础构造函数调用的,而FMyEntries
是null
,因为它自己的构造函数不是{\ 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()函数来解决它。
答案 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 ... }
),但在这种情况下,有要派生类作为通用参数提供。另一种设计气味。