我有一堆导出IModule接口的模块。所以在主程序中我没有问题
...
let mutable modules = Seq.empty
[<ImportMany>]
member x.Modules
with get():IEnumerable<Lazy<IModule, IModuleData>> = modules
and set(a) = modules <- a
...
但是现在我需要将接口暴露回那些模块。因此每个模块都将导入一个接口
...
let mutable parent:IParent = ?
[<Import>]
member x.Parent
with get():IParent = parent
and set(a) = parent <- a
...
所以我的问题是当我没有初始值时,如何创建我的可变“父”?另外,这是将API公开回组件的适当方法吗?
答案 0 :(得分:6)
使用Unchecked.defaultof<_>
应该可以解决问题,但这意味着您正在规避F#类型系统,这可能是一件危险的事情 - 系统会试图阻止您意外解除引用null
值(并获得NullReferenceException
)。
在F#中声明的类型没有null
作为正确的值,这是为了消除由null
引起的常见错误。干净的F#方法是使用选项类型来表示缺少值的事实:
let mutable parent:option<IParent> = None
[<Import>]
member x.Parent
with get():IParent =
match parent with
| Some p -> p
| None -> failwith "TODO: Throw some reasonable exception here!"
and set(a) = parent <- Some(a)
如果您只想说IParent
可以有null
值(也许是因为您需要在某些C#代码中使用它,无论如何都会忽略F#限制),那么您可以标记使用允许使用null
类型的特殊属性的类型定义。
[<AllowNullLiteral>]
type IParent =
abstract DoStuff : unit -> unit
然后你可以写let mutable parent:IParent = null
。这种方法的好处是,您还可以轻松检查某个值是否为null
(仅使用if parent <> null then ...
),这在使用Unchecked.defaultof<_>
时并不明显。
答案 1 :(得分:1)
let mutable parent = Unchecked.defaultof<IParent>
应该这样做。
答案 2 :(得分:0)
跟进Tomas解释的内容,您应该将导入直接放入构造函数中。这将使您的代码更加惯用。