サンプルプログラムの場合:
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と比較すると「タイプ'MyClass'には適切な値としてnullがありません」というエラーが発生します(C#依存性注入との互換性要件のb / c F#オプションタイプに頼ることはできません)。
nullチェックを次のように変更することで、これを簡単に修正できます。
if instance :> obj = null then
しかし、私はこれが完全に「間違っている」ことを知っています(「感じる」)。特に、MyClassが(C#の背景から言えば)ボックス化する必要のない参照型であると考えると。
「F#値の制限」とそれが型推論にどのように影響するかについて読んだことがありますが、それがこのシナリオにどのように適用されるかを光らせることはできません。
Q:これを行う別の方法はありますか?
余談ですが#1:エラーを取得するためのより簡単な方法を見つけました...
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let nullMyClass : MyClass = null
余談ですが、#2:考えずにSystem.Nullableを試しました... MyClassは参照型であり、Nullable <_>が必要とする値型(構造体)ではありません。だから、私は本当に参照型を扱っていることを私に安心させ、なぜオブジェクトキャストが突然これを機能させるのか疑問に思います。
更新:興味のある人のために、私はこれをCommonServiceLocatorの1つのソリューションとして以下の3つの機能で使用しました。要求される各サービスはnull[<AllowNullLiteral>]
をサポートする必要があるため、サービスクラスがF#で定義されている場合は、 :を追加する必要があります。
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