对于这个示例程序:
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let classFactory () = MyClass("up to you")
let live () =
let instance = classFactory()
if instance = null then raise(System.Exception("null is not living... that's why OO languages die from bugs"))
instance
当我将这个类作为隐式类型函数的返回值并将其与null进行比较时,出现错误"The type 'MyClass' does not have null as a proper value"("MyClass"类型没有"null"作为合适的值)。由于需要与C#依赖注入兼容,我不能依赖F#选项类型。我可以通过将null检查改为以下内容轻松修复此问题:
if instance :> obj = null then
然而,我知道(“感觉”)这是完全“错误”的。特别是当考虑到MyClass是一个引用类型,不应该需要被装箱(从C#的背景中说)。
我读过有关“F#值约束”的文章以及它如何影响类型推断,但我似乎无法理解它如何适用于这种情况。
问:还有其他方法可以做到这一点吗?
附注1:我找到了一个更简单的获取错误的方法...
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let nullMyClass : MyClass = null
< p > < em > 另外 #2: 我尝试过使用System.Nullable,但没有考虑到... MyClass是一个引用类型而不是值类型(结构体),这正是Nullable<_>所需要的。所以,这只是向我确认了我确实正在处理一个引用类型,并让我想知道为什么对象转换突然使其工作。
更新: 对于任何有兴趣的人,我使用以下三个函数之一作为Common Service Locator的解决方案之一。每个请求的服务都必须支持null,因此,如果服务类在F#中定义,则需要添加[<AllowNullLiteral>]
:
let private getServiceLocator () =
try Some(Microsoft.Practices.ServiceLocation.ServiceLocator.Current)
with | _ -> None
let private getService serviceFactory =
let serviceLocator = getServiceLocator()
let service = match serviceLocator with
| None -> serviceFactory()
| _ ->
match serviceLocator.Value.GetInstance<'a>() with
| null -> serviceFactory()
| svc -> svc
match service with
| null -> None
| _ -> Some(service)
let private getRequiredService serviceFactory =
let service = getService serviceFactory
match service with
| None -> raise(MissingServiceException(""))
| _ -> service.Value
Option 't
更符合习惯用法。 - John Palmer[<AllowNullLiteral>]
才能按照C#开发人员的期望工作... :( - Eric SwansonAllowNullLiteral
,从C#中可以将类、记录和DUs设置为null值——毕竟,在底层它们仍然是引用类型。该特性只允许从F#中将某些东西设置为null。 - ildjarn