【问题标题】:F# null test fails to detect null valuesF# null 测试无法检测到 null 值
【发布时间】:2015-01-23 22:40:43
【问题描述】:

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

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

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

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#)的回答

【问题讨论】:

标签: .net f# null mono


【解决方案1】:

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

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

解决方法是在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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多