我如何滥用空合并运算符?这是正确评估 "null" 吗?
How am I misusing the null-coalescing operator? Is this evaluating "null" correctly?
我正在尝试在 Unity 的 C# 脚本中使用空合并运算符,我的项目脚本运行时设置为 .NET 4.x,因此它应该可以正常工作。
问题是即使 LEFT 操作数的计算结果为 null,它也不能正确地 return RIGHT 操作数。
这是一个示例语句,当左操作数 return 为空时 不起作用 :
m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );
这是完全相同的语句,除了它显式地将 null 传递给 null 合并运算符(这在 运行 时正常工作)
m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();
这是一个简短的脚本,可以直接在 Unity 中轻松测试问题。
using UnityEngine;
public class DoubleQuestionTest : MonoBehaviour
{
public GameObject myGo;
public MeshFilter m_meshFilter = null;
[ContextMenu( "Test1 Null Coalescing Operator" )]
void Test1()
{
m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );
if ( m_meshFilter == null )
{
Debug.Log( "m_meshFilter was null, trying Alternate" );
m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();
}
}
MeshFilter GetMeshFilter()
{
MeshFilter temp = myGo.GetComponent<MeshFilter>();
if ( temp == null )
Debug.Log( " > Get Mesh Filter RETURNING NULL" );
return temp;
}
MeshFilter AddMeshFilter()
{
Debug.Log( " > Add Mesh Filter Called" );
return myGo.AddComponent<MeshFilter>();
}
}
在Unity(2018.3.12f1)的Inspector中点击Component右上角可以运行测试功能
使用测试脚本时,第一次使用 Null Coalescing 运算符会失败,但第二次成功时我明确检查 null,然后冗余地传递 null(使用三元运算符)
Unity 编辑器控制台中的输出:
!
这是一个错误吗?还是我做错了什么?
_______________________________
编辑:
在寻找解决方法的过程中,我找到了一个不错的方法来使 return REAL null 为了 null 合并运算符:
public static T GetComponentRealNull<T>( this GameObject self ) where T : Component
{
T component = self.GetComponent<T>();
if ( component == null )
return null;
return component;
}
或者对于 adding/getting 组件的更具体情况:
public static T GetComponentOrAddIfMissing<T>(this GameObject self) where T : Component
{
T component = self.GetComponent<T>();
if(component == null)
component = self.AddComponent<T>();
return component;
}
这是 Unity 搞砸了。
如果你这样做:
MeshFilter GetMeshFilter()
{
MeshFilter temp = myGo.GetComponent<MeshFilter>();
if ( temp == null ) {
Debug.Log( " > Get Mesh Filter RETURNING NULL" );
return null;
}
return temp;
}
有效。
为什么?
因为 Unity 已覆盖所有 Unity 对象的 Equals
(和 ==
运算符),因此 destroyed game objects 并且 never existing objects 都“等于”null(这样做是为了让开发人员的生活更轻松)。但是被销毁(或“丢失”)的对象并不是字面上的 null:它是引擎 C# 部分中的一个包装对象,指向底层 C++ 代码中的 null 对象。空合并运算符检查 字面上的空值。
例如试试这个:
Start() {
GameObject gg = new GameObject(); //create a GO
DestroyImmediate(gg); //destroy it immediately
Debug.Log(gg == null); //prints true: it is definitely null!
GameObject go = gg ?? this.gameObject; //get a non-null object
Debug.Log(go); //prints null
}
这也是为什么当您尝试访问为 null 的 Unity 对象时得到 MissingReferenceException 而不是 NullReferenceException 的原因:这些对象并非字面上 null,而只是 有效无效。
一般来说,这就是 Object.bool
operator 的用途。只是更喜欢使用它而不是 null
检查:
public static T GetComponentOrAddIfMissing<T>(this GameObject self) where T : Component
{
T component = self.GetComponent<T>();
if(!component) component = self.AddComponent<T>();
return component;
}
我正在尝试在 Unity 的 C# 脚本中使用空合并运算符,我的项目脚本运行时设置为 .NET 4.x,因此它应该可以正常工作。
问题是即使 LEFT 操作数的计算结果为 null,它也不能正确地 return RIGHT 操作数。
这是一个示例语句,当左操作数 return 为空时 不起作用 :
m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );
这是完全相同的语句,除了它显式地将 null 传递给 null 合并运算符(这在 运行 时正常工作)
m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();
这是一个简短的脚本,可以直接在 Unity 中轻松测试问题。
using UnityEngine;
public class DoubleQuestionTest : MonoBehaviour
{
public GameObject myGo;
public MeshFilter m_meshFilter = null;
[ContextMenu( "Test1 Null Coalescing Operator" )]
void Test1()
{
m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );
if ( m_meshFilter == null )
{
Debug.Log( "m_meshFilter was null, trying Alternate" );
m_meshFilter = ( GetMeshFilter() == null ? null : GetMeshFilter() ) ?? AddMeshFilter();
}
}
MeshFilter GetMeshFilter()
{
MeshFilter temp = myGo.GetComponent<MeshFilter>();
if ( temp == null )
Debug.Log( " > Get Mesh Filter RETURNING NULL" );
return temp;
}
MeshFilter AddMeshFilter()
{
Debug.Log( " > Add Mesh Filter Called" );
return myGo.AddComponent<MeshFilter>();
}
}
在Unity(2018.3.12f1)的Inspector中点击Component右上角可以运行测试功能
使用测试脚本时,第一次使用 Null Coalescing 运算符会失败,但第二次成功时我明确检查 null,然后冗余地传递 null(使用三元运算符)
Unity 编辑器控制台中的输出:
这是一个错误吗?还是我做错了什么?
_______________________________
编辑:
在寻找解决方法的过程中,我找到了一个不错的方法来使 return REAL null 为了 null 合并运算符:
public static T GetComponentRealNull<T>( this GameObject self ) where T : Component
{
T component = self.GetComponent<T>();
if ( component == null )
return null;
return component;
}
或者对于 adding/getting 组件的更具体情况:
public static T GetComponentOrAddIfMissing<T>(this GameObject self) where T : Component
{
T component = self.GetComponent<T>();
if(component == null)
component = self.AddComponent<T>();
return component;
}
这是 Unity 搞砸了。
如果你这样做:
MeshFilter GetMeshFilter()
{
MeshFilter temp = myGo.GetComponent<MeshFilter>();
if ( temp == null ) {
Debug.Log( " > Get Mesh Filter RETURNING NULL" );
return null;
}
return temp;
}
有效。
为什么?
因为 Unity 已覆盖所有 Unity 对象的 Equals
(和 ==
运算符),因此 destroyed game objects 并且 never existing objects 都“等于”null(这样做是为了让开发人员的生活更轻松)。但是被销毁(或“丢失”)的对象并不是字面上的 null:它是引擎 C# 部分中的一个包装对象,指向底层 C++ 代码中的 null 对象。空合并运算符检查 字面上的空值。
例如试试这个:
Start() {
GameObject gg = new GameObject(); //create a GO
DestroyImmediate(gg); //destroy it immediately
Debug.Log(gg == null); //prints true: it is definitely null!
GameObject go = gg ?? this.gameObject; //get a non-null object
Debug.Log(go); //prints null
}
这也是为什么当您尝试访问为 null 的 Unity 对象时得到 MissingReferenceException 而不是 NullReferenceException 的原因:这些对象并非字面上 null,而只是 有效无效。
一般来说,这就是 Object.bool
operator 的用途。只是更喜欢使用它而不是 null
检查:
public static T GetComponentOrAddIfMissing<T>(this GameObject self) where T : Component
{
T component = self.GetComponent<T>();
if(!component) component = self.AddComponent<T>();
return component;
}