F#null测试无法检测到空值

时间:2015-01-23 22:40:43

标签: .net f# null mono

在F#中对null进行稳健测试的正确方法是什么?

我有一个基于Unity游戏引擎(这是一个闭源单声道c#/ c ++引擎)的混合F#/ C#项目。

我有一个F#函数调用可能返回null的Unity API函数。 Unity函数返回null,但我的F#代码无法检测到(我从测试数据的形状,附加调试器,插入日志语句等都知道这一点)。我写的每个空测试似乎在它应该为真时返回false。首先尝试:

let rec FindInParents<'t when 't : null> (go : GameObject) = 
    match go with 
    | null -> null
    | _ ->
        let comp = go.GetComponent<'t>() // GetComponent returns null
        match comp with
        | null -> FindInParents (go.transform.parent.gameObject) // This should be matched but isn't
        | _ -> comp // Always this branch

我也试过以下内容但没有成功:

let rec FindInParents<'t when 't : null> (go : GameObject) = 
    if obj.ReferenceEquals (go, Unchecked.defaultof<'t>) then null 
    else 
        let comp = go.GetComponent<'t>() // Comp is null
        if obj.ReferenceEquals (comp, Unchecked.defaultof<'t>) then FindInParents<'t> (go.transform.parent.gameObject)
        else comp // Always this branch

我觉得我在这里遗漏了一些基本的东西,但到目前为止,我已经躲过了。有什么指针吗?

编辑:我还应该指出,GetComponent始终返回UnityEngine.Component的子类型,并且始终是引用类型。 UnityEngine.Component是UnityEngine.Object的子类型,它定义了一个自定义==运算符(我不认为这是相关的,因为在第二个例子中不应该调用==(参见Daniel的答案) [Handling Null Values in F#

1 个答案:

答案 0 :(得分:1)

原来,Unity对非托管端已销毁但尚未在托管端收集的对象使用伪空值。自定义== / !=运算符检查伪空值。

对于像问题中那样的泛型函数,F#将使用IL指令进行空值测试(brfalse.s) - 这显然不会检测Unity伪空值。对null的测试明确导致对LanguagePrimitives.HashCompare.GenericEqualityIntrinsic的调用,该调用也不知道Unity假空值。

解决方案是在unity对象上调用Equals以确保调用重载的Unity运算符:

let isUnityNull x = 
    let y = box x // In case of value types
    obj.ReferenceEquals (y, Unchecked.defaultof<_>) || // Regular null check
    y.Equals(Unchecked.defaultof<_>) // Will call Unity overload if needed