# Null 引用

> Understand what causes a NullReferenceException in C# and how to avoid uninitialized object references.

尝试访问值为 `null` 的类型的成员时，C# 中会发生 `NullReferenceException`。在运行时出现 `NullReferenceException` 通常意味着在使用对象引用变量之前忘记初始化该变量。有关产生 null 引用的常见编码错误的完整解释，请参阅 [Microsoft 文档](https://learn.microsoft.com/en-us/dotnet/api/system.nullreferenceexception?view=net-8.0)。

Null 引用错误消息如下所示：

```
NullReferenceException: Object reference not set to an instance of an object
    at Example.Start () [0x0000b] in /Unity/projects/nre/Assets/Example.cs:10 
```

此错误消息指出脚本文件 `Example.cs` 的第 10 行发生 `NullReferenceException`，该异常发生在 `Start()` 函数内部。根据这些信息，比较容易查找和修复 Null 引用异常。在此示例中，代码为：

```lang-csharp
using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {

    // Use this for initialization
	void Start () {
		GameObject myGameObject = GameObject.Find("exampleGameObject");
    	Debug.Log(myGameObject.name);
    }
	
}
```

代码会查找名为“exampleGameObject”的游戏对象。在此示例中不存在该名称的游戏对象，因此 `Find()` 函数返回 `null`。在下一行（第 9 行），我们使用 `myGameObject` 变量并尝试打印出其引用的游戏对象的名称。由于 Unity 正在尝试访问不存在的游戏对象，因此会返回 `NullReferenceException`

## Null 检查

此示例中的解决方案是，在给定名称的游戏对象不存在的情况下包含结果。以下脚本将检查 `go` 变量是否返回 `null`，如果是，则显示一条消息：

```lang-csharp
using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {

    void Start () {
	    GameObject myGameObject = GameObject.Find("exampleGameObject");
		if (myGameObject == null) {
			Debug.Log("No GameObject called exampleGameObject found");
    	} else {
			Debug.Log(myGameObject.name);
    	}
    }
    	
}
```

### 自定义 == 运算符

对于继承自 [UnityEngine.Object](/engine/6000.0/manual/scripting/get-started/fundamental-unity-types/class-object.md) 的类型，Unity 使用 C# [相等和不等运算符](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators)的自定义版本。这意味着，即使 `myGameObject` 在技术上持有有效的 C# 对象引用，上述示例 (`myGameObject == null`) 中的 null 检查也可以对 `true` 求值（反过来，`myGameObject != null` 也可以对 `false` 求值）。在以下两种情况下会发生这种情况：

1. 对象可以是所谓的“假 null”或占位对象，Unity 在编辑器中仅用于填充未初始化的 MonoBehaviour 字段。这些对象可存储有用的调试信息，以便在您尝试引用这些字段时帮助您找到这些字段的来源。
2. 对象可以是托管 (C#) 对象，该对象尚未进行垃圾收集，但由于非托管 (C++) 对应对象已被销毁，因此应被视为 null。

## Try/Catch 代码块

如果使用需要在**检视面板 (Inspector)** 窗口中初始化的变量，Unity 也会调用 `NullReferenceException`。如果忘记这样做，则变量将为 `null`。处理 `NullReferenceException` 的另一种方法是使用 `try`/`catch` 代码块。例如：

```lang-csharp
using UnityEngine;
using System;
using System.Collections;

public class Example2 : MonoBehaviour {

    public Light myLight; // set in the inspector
	
	void Start () {
		try {
			myLight.color = Color.yellow;
    	}		
    	catch (NullReferenceException ex) {
	    	Debug.Log("myLight was not set in the inspector");
		}
	}
	
}
```

在此代码示例中，名为 `myLight` 的变量是需要在检视面板窗口中设置的 `Light`。如果未设置此变量，则默认为 `null`。

若尝试在 `try` 代码块中改变光源的颜色，则会导致 `NullReferenceException`。如果发生这种情况，`catch` 代码块会显示一条消息，提醒您在检视面板中设置光源。

## 其他资源

* [UnityEngine.Object](/engine/6000.0/manual/scripting/get-started/fundamental-unity-types/class-object.md)
