我试图在Unity中的C#脚本中使用null-coalescing运算符,我的项目Scripting Runtime设置为.NET 4.x,因此它应该可以正常工作。
问题在于,即使LEFT操作数计算为null,也无法正确返回RIGHT操作数。
这是一个示例语句,当左操作数返回null时,不起作用:
m_meshFilter = ( GetMeshFilter() ?? AddMeshFilter() );
这里是SAME确切的语句,除了它显式地将null传递给null-coalescing运算符(运行时正确运行)
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)中的检查器中单击组件的右上角来运行测试功能
使用测试脚本时,第一次使用Null Coalescing运算符将失败,但是当我显式检查null,然后(通过三元运算符)冗余地传递null时,第二次使用会成功
Unity编辑器控制台中的输出:
!
这是一个错误吗?还是我做错了什么?
_______________________________
编辑:
在寻找解决方法时,我找到了一种不错的方法,以使null运算符成为return REAL null:
public static T GetComponentRealNull<T>( this GameObject self ) where T : Component
{
T component = self.GetComponent<T>();
if ( component == null )
return null;
return component;
}
或者对于添加/获取组件的更具体的情况:
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;
}
答案 0 :(得分:6)
如果您这样做:
MeshFilter GetMeshFilter()
{
MeshFilter temp = myGo.GetComponent<MeshFilter>();
if ( temp == null ) {
Debug.Log( " > Get Mesh Filter RETURNING NULL" );
return null;
}
return temp;
}
有效。
为什么?
因为Unity在所有Unity对象上都覆盖了Equals
(和==
运算符),所以被破坏的游戏对象和从不存在的对象两者都等于等于null(这样做是为了使开发人员的生活更轻松)。但是,被破坏(或“丢失”)的对象不是 literally 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而不是NullReferenceException的Unity对象时会得到MissingReferenceException的原因:这些对象不是 literally null,而是有效的 null。