Loại giá trị so với loại tham chiếu
Trong nhiều ngôn ngữ lập trình, các biến có cái gọi là "kiểu dữ liệu". Hai kiểu dữ liệu chính là kiểu giá trị (int, float, bool, char, struct, ...) và kiểu tham chiếu (thể hiện của các lớp). Mặc dù các loại giá trị chứa chính giá trị , các tham chiếu chứa địa chỉ bộ nhớ trỏ đến một phần bộ nhớ được phân bổ để chứa một tập hợp các giá trị (tương tự như C / C ++).
Ví dụ: Vector3
là một loại giá trị (một cấu trúc có chứa tọa độ và một số hàm) trong khi các thành phần được đính kèm với GameObject của bạn (bao gồm các tập lệnh tùy chỉnh kế thừa từ MonoBehaviour
) là loại tham chiếu.
Khi nào tôi có thể có NullReferenceException?
NullReferenceException
được ném khi bạn cố truy cập vào một biến tham chiếu không tham chiếu đến bất kỳ đối tượng nào, do đó nó là null (địa chỉ bộ nhớ được trỏ đến 0).
Một số nơi phổ biến NullReferenceException
sẽ được nâng lên:
Thao tác với GameObject / Thành phần chưa được chỉ định trong thanh tra
// 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();
}
Lấy một thành phần không được đính kèm với GameObject và sau đó, cố gắng thao túng nó:
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 ;
}
Truy cập GameObject không tồn tại:
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";
}
Lưu ý: Hãy cẩn thận, GameObject.Find
, GameObject.FindWithTag
, GameObject.FindObjectOfType
chỉ trả lại gameObjects được kích hoạt trong hệ thống phân cấp khi hàm được gọi.
Cố gắng sử dụng kết quả của một getter đang trở lại 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.
Truy cập một phần tử của mảng không khởi tạo
private GameObject[] myObjects ; // Uninitialized array
private void Start()
{
for( int i = 0 ; i < myObjects.Length ; ++i )
Debug.Log( myObjects[i].name ) ;
}
Ít phổ biến hơn, nhưng gây phiền nhiễu nếu bạn không biết về đại biểu 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) ;
}
Làm thế nào để khắc phục ?
Nếu bạn đã hiểu các đoạn trước, bạn sẽ biết cách sửa lỗi: đảm bảo biến của bạn đang tham chiếu (trỏ đến) một thể hiện của một lớp (hoặc chứa ít nhất một hàm cho các đại biểu).
Nói dễ hơn làm? Vâng, thực sự. Dưới đây là một số lời khuyên để tránh và xác định vấn đề.
Cách "bẩn": Phương pháp thử & bắt:
Collider collider = gameObject.GetComponent<Collider>();
try
{
collider.enabled = false ;
}
catch (System.NullReferenceException exception) {
Debug.LogError("Oops, there is no collider attached", this) ;
}
Cách "sạch" hơn (IMHO): Kiểm tra
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) ;
}
Khi gặp lỗi bạn không thể giải quyết, luôn luôn là một ý tưởng tốt để tìm ra nguyên nhân của vấn đề. Nếu bạn "lười biếng" (hoặc nếu vấn đề có thể được giải quyết dễ dàng), hãy sử dụng Debug.Log
để hiển thị trên thông tin bảng điều khiển sẽ giúp bạn xác định những gì có thể gây ra sự cố. Một cách phức tạp hơn là sử dụng Breakpoint và Debugger của IDE của bạn.
Sử dụng Debug.Log
là khá hữu ích để xác định chức năng nào được gọi đầu tiên chẳng hạn. Đặc biệt là nếu bạn có một chức năng chịu trách nhiệm khởi tạo các trường. Nhưng đừng quên loại bỏ chúng Debug.Log
để tránh làm lộn xộn bảng điều khiển của bạn (và vì lý do hiệu suất).
Một lời khuyên khác, đừng ngần ngại "cắt" các cuộc gọi chức năng của bạn và thêm Debug.Log
để thực hiện một số kiểm tra.
Thay vì :
GameObject.Find("MyObject").GetComponent<MySuperComponent>().value = "foo" ;
Làm điều này để kiểm tra nếu mọi tham chiếu được đặt:
GameObject myObject = GameObject.Find("MyObject") ;
Debug.Log( myObject ) ;
MySuperComponent superComponent = myObject.GetComponent<MySuperComponent>() ;
Debug.Log( superComponent ) ;
superComponent.value = "foo" ;
Thậm chí còn tốt hơn :
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 ) ;
}
Nguồn:
- http://answers.unity3d.com/questions/47830/what-is-a-null-reference-exception-in-unity.html
- /programming/218384/what-is-a-nullpulumexception-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