F#可变,没有MEF的初始值

时间:2011-11-11 22:31:49

标签: f# mef

我有一堆导出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公开回组件的适当方法吗?

3 个答案:

答案 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解释的内容,您应该将导入直接放入构造函数中。这将使您的代码更加惯用。