値タイプと参照タイプ
多くのプログラミング言語では、変数にはいわゆる「データ型」があります。2つの主要なデータ型は、値の型(int、float、bool、char、structなど)と参照型(クラスのインスタンス)です。値タイプには値自体が含まれますが、参照には、値のセットを含むために割り当てられたメモリの一部を指すメモリアドレスが含まれます(C / C ++と同様)。
たとえば、Vector3
は値型(座標といくつかの関数を含む構造体)ですが、GameObjectにアタッチされたコンポーネント(から継承するカスタムスクリプトを含むMonoBehaviour
)は参照型です。
NullReferenceExceptionはいつ発生しますか?
NullReferenceException
オブジェクトを参照していない参照変数にアクセスしようとするとスローされるため、nullになります(メモリアドレスが0を指している)。
いくつかの一般的な場所NullReferenceException
が発生します:
インスペクターで指定されていないゲームオブジェクト/コンポーネントの操作
// t is a reference to a Transform.
public Transform t ;
private void Awake()
{
// If you do not assign something to t
// (either from the Inspector or using GetComponent), t is null!
t.Translate();
}
GameObjectにアタッチされていないコンポーネントを取得して、それを操作しようとしています:
private void Awake ()
{
// Here, you try to get the Collider component attached to your gameobject
Collider collider = gameObject.GetComponent<Collider>();
// But, if you haven't any collider attached to your gameobject,
// GetComponent won't find it and will return null, and you will get the exception.
collider.enabled = false ;
}
存在しないGameObjectへのアクセス:
private void Start()
{
// Here, you try to get a gameobject in your scene
GameObject myGameObject = GameObject.Find("AGameObjectThatDoesntExist");
// If no object with the EXACT name "AGameObjectThatDoesntExist" exist in your scene,
// GameObject.Find will return null, and you will get the exception.
myGameObject.name = "NullReferenceException";
}
注:して気をつけて、GameObject.Find
、GameObject.FindWithTag
、GameObject.FindObjectOfType
のみされているゲームオブジェクトを返す有効な関数が呼び出されたときの階層では。
返ってくるゲッターの結果を使おうとするとnull
:
var fov = Camera.main.fieldOfView;
// main is null if no enabled cameras in the scene have the "MainCamera" tag.
var selection = EventSystem.current.firstSelectedGameObject;
// current is null if there's no active EventSystem in the scene.
var target = RenderTexture.active.width;
// active is null if the game is currently rendering straight to the window, not to a texture.
初期化されていない配列の要素にアクセスする
private GameObject[] myObjects ; // Uninitialized array
private void Start()
{
for( int i = 0 ; i < myObjects.Length ; ++i )
Debug.Log( myObjects[i].name ) ;
}
あまり一般的ではありませんが、C#デリゲートについて知らなければ面倒です。
delegate double MathAction(double num);
// Regular method that matches signature:
static double Double(double input)
{
return input * 2;
}
private void Awake()
{
MathAction ma ;
// Because you haven't "assigned" any method to the delegate,
// you will have a NullReferenceException
ma(1) ;
ma = Double ;
// Here, the delegate "contains" the Double method and
// won't throw an exception
ma(1) ;
}
直し方 ?
前の段落を理解していれば、エラーを修正する方法がわかります。変数がクラスのインスタンスを参照(または参照)している(またはデリゲート用の関数が少なくとも1つ含まれている)ことを確認してください。
言うより簡単ですか?はい、そうです。問題を回避して特定するためのヒントをいくつか紹介します。
「汚い」方法:try&catchメソッド:
Collider collider = gameObject.GetComponent<Collider>();
try
{
collider.enabled = false ;
}
catch (System.NullReferenceException exception) {
Debug.LogError("Oops, there is no collider attached", this) ;
}
「よりクリーン」な方法(IMHO):チェック
Collider collider = gameObject.GetComponent<Collider>();
if(collider != null)
{
// You can safely manipulate the collider here
collider.enabled = false;
}
else
{
Debug.LogError("Oops, there is no collider attached", this) ;
}
解決できないエラーが発生した場合は、常に問題の原因を見つけることをお勧めします。「怠惰」な場合(または問題を簡単に解決できる場合)は、を使用Debug.Log
してコンソールに情報を表示し、問題の原因を特定するのに役立ちます。より複雑な方法は、IDEのブレークポイントとデバッガーを使用することです。
Debug.Log
たとえば、どの関数が最初に呼び出されるかを判断するために使用すると非常に便利です。特に、フィールドの初期化を担当する関数がある場合。ただしDebug.Log
、コンソールが雑然としないように(パフォーマンス上の理由で)これらを削除することを忘れないでください。
別のアドバイスとして、関数呼び出しを「カット」Debug.Log
して、チェックを追加することをためらわないでください。
の代わりに :
GameObject.Find("MyObject").GetComponent<MySuperComponent>().value = "foo" ;
これを実行して、すべての参照が設定されているかどうかを確認します。
GameObject myObject = GameObject.Find("MyObject") ;
Debug.Log( myObject ) ;
MySuperComponent superComponent = myObject.GetComponent<MySuperComponent>() ;
Debug.Log( superComponent ) ;
superComponent.value = "foo" ;
さらに良い:
GameObject myObject = GameObject.Find("MyObject") ;
if( myObject != null )
{
MySuperComponent superComponent = myObject.GetComponent<MySuperComponent>() ;
if( superComponent != null )
{
superComponent.value = "foo" ;
}
else
{
Debug.Log("No SuperComponent found onMyObject!");
}
}
else
{
Debug.Log("Can't find MyObject!", this ) ;
}
出典:
- http://answers.unity3d.com/questions/47830/what-is-a-null-reference-exception-in-unity.html
- /programming/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it/218510#218510
- https://support.unity3d.com/hc/en-us/articles/206369473-NullReferenceException
- https://unity3d.com/fr/learn/tutorials/topics/scripting/data-types