ชนิดของค่าเทียบกับชนิดของการอ้างอิง
ในภาษาการเขียนโปรแกรมหลายตัวแปรตัวแปรมีสิ่งที่เรียกว่า "ชนิดข้อมูล" ชนิดข้อมูลหลักสองชนิดคือชนิดของค่า (int, float, bool, char, struct, ... ) และประเภทการอ้างอิง (อินสแตนซ์ของคลาส) ในขณะที่ชนิดของค่ามีค่าตัวเองการอ้างอิงประกอบด้วยที่อยู่หน่วยความจำที่ชี้ไปยังส่วนของหน่วยความจำที่จัดสรรให้มีชุดของค่า (คล้ายกับ C / C ++)
ตัวอย่างเช่นVector3
เป็นประเภทค่า (โครงสร้างที่มีพิกัดและฟังก์ชั่นบางอย่าง) ในขณะที่ส่วนประกอบที่แนบมากับ GameObject ของคุณ (รวมถึงสคริปต์ที่กำหนดเองของคุณที่สืบทอดมาจากMonoBehaviour
) เป็นประเภทอ้างอิง
เมื่อใดที่ฉันสามารถมี NullReferenceException
NullReferenceException
จะถูกโยนทิ้งเมื่อคุณพยายามเข้าถึงตัวแปรอ้างอิงที่ไม่ได้อ้างอิงวัตถุใด ๆ ดังนั้นจึงเป็นโมฆะ (ที่อยู่หน่วยความจำชี้ไปที่ 0)
สถานที่ทั่วไปบางแห่งNullReferenceException
จะได้รับการยก:
การจัดการ GameObject / Component ที่ไม่ได้ระบุไว้ในสารวัตร
// 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
เพียงกลับ gameObjects ที่มีการเปิดใช้งานในลำดับชั้นเมื่อฟังก์ชั่นที่เรียกว่า
กำลังพยายามใช้ผลลัพธ์ของผู้ทะเยอทะยานที่กลับมา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) ;
}
จะแก้ไขอย่างไร
หากคุณเข้าใจย่อหน้าก่อนหน้านี้คุณรู้วิธีแก้ไขข้อผิดพลาด: ตรวจสอบให้แน่ใจว่าตัวแปรของคุณอ้างอิง (ชี้ไปที่) ตัวอย่างของคลาส (หรือมีอย่างน้อยหนึ่งฟังก์ชั่นสำหรับผู้รับมอบสิทธิ์)
พูดง่ายกว่าทำ? ใช่แน่นอน. นี่คือเคล็ดลับที่จะหลีกเลี่ยงและระบุปัญหา
วิธี "สกปรก": วิธีลองและจับ:
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