斯科特的答案与你正在做的非常接近,并得出了这个答案。 虽然缺少这么多东西。 您需要做更多工作才能使该脚本正常工作。
1. 您需要使用Resources.FindObjectsOfTypeAll
获取场景中的所有按钮(包括非活动/禁用的按钮)。
2. 浏览按钮,检查保存该function的类/脚本是否存在reflection。 你这样做是因为有时我们重命名脚本。 这可能会导致问题。 显示脚本的消息不存在。
你可以通过简单地检查Type.GetType(className);
是null
。
如果它为null
则甚至不进行下面的测试,因为包含Button
的onClick
函数的组件已被重命名。 显示一条错误消息,指出此脚本已被删除或重命名。
3. 如果该类存在,现在检查该函数是否存在于该按钮的onClick
事件中注册的class
中的reflection。
这可以通过简单地检查type.GetMethod(functionName);
是null
。
如果函数存在,那么Button就可以了。 如果函数存在,则不必显示消息。 停在这里。
如果返回null
则继续#4 。
4. 检查函数是否存在,但这一次,检查函数是否使用private
访问修饰符 声明。
这是人们犯的典型错误。 他们将function声明为public
,通过编辑器分配,然后错误地将其从public
更改为private
。 这应该工作,但将来可能会导致问题。
这可以通过简单地检查type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic);
是null
。
如果该函数存在,则显示一条消息,警告您此函数的访问修饰符已从public
更改为private
,应更改回public
。
如果该函数不存在,则显示一条消息,警告您此函数不再存在或已重命名。
下面是一个执行上面提到的所有内容的脚本。 将它附加到一个空的GameObject ,它将在编辑器中运行游戏时随时执行。
using System; using System.Reflection; using UnityEngine; using UnityEngine.UI; public class MissingOnClickDetector : MonoBehaviour { void Awake() { //Debug.Log("Class exist? " + classExist("ok.ButtonCallBackTest")); searchForMissingOnClickFunctions(); } void searchForMissingOnClickFunctions() { //Find all Buttons in the scene including hiding ones Button[] allButtonScriptsInScene = Resources.FindObjectsOfTypeAll() as Button[]; for (int i = 0; i < allButtonScriptsInScene.Length; i++) { detectButtonError(allButtonScriptsInScene[i]); } } //Searches each registered onClick function in each class void detectButtonError(Button button) { for (int i = 0; i < button.onClick.GetPersistentEventCount(); i++) { //Get the target class name UnityEngine.Object objectName = button.onClick.GetPersistentTarget(i); //Get the function name string methodName = button.onClick.GetPersistentMethodName(i); ; //////////////////////////////////////////////////////CHECK CLASS/SCRIPT EXISTANCE///////////////////////////////////////// //Check if the class that holds the function is null then exit if it is if (objectName == null) { Debug.Log("Button \"" + button.gameObject.name + "\" is missing the script that has the supposed button callback function. " + "Please check if this script still exist or has been renamed", button.gameObject); continue; //Don't run code below } //Get full target class name(including namespace) string objectFullNameWithNamespace = objectName.GetType().FullName; //Check if the class that holds the function exist then exit if it does not if (!classExist(objectFullNameWithNamespace)) { Debug.Log("Button \"" + button.gameObject.name + "\" is missing the script that has the supposed button callback function. " + "Please check if this script still exist or has been renamed", button.gameObject); continue; //Don't run code below } //////////////////////////////////////////////////////CHECK FUNCTION EXISTANCE///////////////////////////////////////// //Check if function Exist as public (the registered onClick function is ok if this returns true) if (functionExistAsPublicInTarget(objectName, methodName)) { //No Need to Log if function exist //Debug.Log("Function Exist"); } //Check if function Exist as private else if (functionExistAsPrivateInTarget(objectName, methodName)) { Debug.Log("The registered Function \"" + methodName + "\" Exist as a private function. Please change \"" + methodName + "\" function from the \"" + objectFullNameWithNamespace + "\" script to a public Access Modifier", button.gameObject); } //Function does not even exist at-all else { Debug.Log("The \"" + methodName + "\" function Does NOT Exist in the \"" + objectFullNameWithNamespace + "\" script", button.gameObject); } } } //Checks if class exit or has been renamed bool classExist(string className) { Type myType = Type.GetType(className); return myType != null; } //Checks if functions exist as public function bool functionExistAsPublicInTarget(UnityEngine.Object target, string functionName) { Type type = target.GetType(); MethodInfo targetinfo = type.GetMethod(functionName); return targetinfo != null; } //Checks if functions exist as private function bool functionExistAsPrivateInTarget(UnityEngine.Object target, string functionName) { Type type = target.GetType(); MethodInfo targetinfo = type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic); return targetinfo != null; } }
你可以扩展按钮类并检查事件计数+方法名称,如果名称包含缺失,则触发错误
using UnityEngine.UI; public class SafeButton : Button { override protected void Awake() { for (int i = 0; i < onClick.GetPersistentEventCount(); i++) { var methodName = onClick.GetPersistentMethodName(i); // if method name contains "missing" // -> Log Error } } }