我有一堆导出IModule接口的模块.所以在主程序中我没有问题
...
let mutable modules = Seq.empty
[<ImportMany>]
member x.Modules
with get():IEnumerable<Lazy<IModule, IModuleData>> = modules
and set(a) = modules <- a
...
Run Code Online (Sandbox Code Playgroud)
但是现在我需要将一个接口公开给那些模块.因此每个模块都将导入一个接口
...
let mutable parent:IParent = ?
[<Import>]
member x.Parent
with get():IParent = parent
and set(a) = parent <- a
...
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,当我没有初始值时,如何创建我的可变"父"?此外,这是将API公开回组件部分的适当方法吗?
使用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)
Run Code Online (Sandbox Code Playgroud)
如果你只想说IParent
可以有一个null
值(也许是因为你需要在一些C#代码中使用它而忽略了F#限制),那么你可以使用允许null
与类型一起使用的特殊属性来标记类型定义.
[<AllowNullLiteral>]
type IParent =
abstract DoStuff : unit -> unit
Run Code Online (Sandbox Code Playgroud)
然后你就可以写了let mutable parent:IParent = null
.这种方法的好处是,您还可以轻松检查一个值是否null
(仅使用if parent <> null then ...
)在您使用时不是那么明显Unchecked.defaultof<_>
.