C# 移除BoxCollider时Unity3D缺少引用异常

C# 移除BoxCollider时Unity3D缺少引用异常,c#,exception,unity3d,editor,components,C#,Exception,Unity3d,Editor,Components,我正在为Unity3D开发一个开源编辑器工具,我正在编写一个CustomEditor 我创建一个主游戏对象,并将脚本附加到它。此脚本通过BoxCollider附加到同一游戏对象 在我的CustomEditor代码中,我有一个方法,负责在完成编辑之前删除附加的两个组件 代码如下: private void FinalizeStairs () { Undo.SetCurrentGroupName("Finalize stairs"); BoxStair

我正在为Unity3D开发一个开源编辑器工具,我正在编写一个CustomEditor

我创建一个主游戏对象,并将脚本附加到它。此脚本通过BoxCollider附加到同一游戏对象

在我的CustomEditor代码中,我有一个方法,负责在完成编辑之前删除附加的两个组件

代码如下:

    private void FinalizeStairs ()
    {
        Undo.SetCurrentGroupName("Finalize stairs");
        BoxStairs script = (BoxStairs)target;
        GameObject go = script.gameObject;
        BoxCollider bc = go.GetComponent<BoxCollider>();

        if (bc != null)
        {
            Undo.DestroyObjectImmediate(bc);
        }
        Undo.DestroyObjectImmediate(target);
    }
    /*
     * This method creates a disabled BoxCollider which marks the volume defined by
     * StairsWidth, StairsHeight, StairsDepth.
     */
    private void AddSelectionBox ()
    {
        BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();

        if (VolumeBox == null)
        {
            VolumeBox = Root.AddComponent<BoxCollider>();
        }

        if (Pivot == PivotType.Downstairs)
        {
            VolumeBox.center = new Vector3(0, StairsHeight * 0.5f, StairsDepth * 0.5f);
        }
        else
        {
            VolumeBox.center = new Vector3(0, -StairsHeight * 0.5f, -StairsDepth * 0.5f);
        }

        VolumeBox.size = new Vector3(StairsWidth, StairsHeight, StairsDepth);

        VolumeBox.enabled = false;
    }
这两个方法都在类上

[CustomEditor(typeof(BoxStairs))]
public sealed class BoxStairsEditor : Editor
它实际上会删除这两个组件,但一旦删除BoxCollider,就会出现以下错误:

MissingReferenceException: The object of type 'BoxCollider' has been 
destroyed but you are still trying to access it.
我试图通过查看跟踪来定位错误发生的位置:

Your script should either check if it is null or you should not destroy the object.
UnityEditor.Editor.IsEnabled () (at C:/buildslave/unity/build/Editor/Mono/Inspector/Editor.cs:590)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1154)
UnityEditor.InspectorWindow.DrawEditors (UnityEditor.Editor[] editors) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1030)
UnityEditor.InspectorWindow.OnGUI () (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:352)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
但是上面没有我的脚本

我一直在看我引用BoxCollider的代码,唯一的地方是创建它的地方,当创建楼梯时,它会在检查器上发生更改时触发

它在课堂上:

[ExecuteInEditMode]
[SelectionBase]
public sealed class BoxStairs : MonoBehaviour
代码如下:

    private void FinalizeStairs ()
    {
        Undo.SetCurrentGroupName("Finalize stairs");
        BoxStairs script = (BoxStairs)target;
        GameObject go = script.gameObject;
        BoxCollider bc = go.GetComponent<BoxCollider>();

        if (bc != null)
        {
            Undo.DestroyObjectImmediate(bc);
        }
        Undo.DestroyObjectImmediate(target);
    }
    /*
     * This method creates a disabled BoxCollider which marks the volume defined by
     * StairsWidth, StairsHeight, StairsDepth.
     */
    private void AddSelectionBox ()
    {
        BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();

        if (VolumeBox == null)
        {
            VolumeBox = Root.AddComponent<BoxCollider>();
        }

        if (Pivot == PivotType.Downstairs)
        {
            VolumeBox.center = new Vector3(0, StairsHeight * 0.5f, StairsDepth * 0.5f);
        }
        else
        {
            VolumeBox.center = new Vector3(0, -StairsHeight * 0.5f, -StairsDepth * 0.5f);
        }

        VolumeBox.size = new Vector3(StairsWidth, StairsHeight, StairsDepth);

        VolumeBox.enabled = false;
    }
/*
*此方法创建一个禁用的BoxCollider,它标记由定义的卷
*楼梯宽度、楼梯高度、楼梯深度。
*/
私有void AddSelectionBox()
{
BoxCollider VolumeBox=Root.GetComponent();
if(VolumeBox==null)
{
VolumeBox=Root.AddComponent();
}
if(Pivot==PivotType.down)
{
VolumeBox.center=新矢量3(0,楼梯高度*0.5f,楼梯深度*0.5f);
}
其他的
{
VolumeBox.center=新矢量3(0,-楼梯高度*0.5f,-楼梯深度*0.5f);
}
VolumeBox.size=新矢量3(楼梯宽度、楼梯高度、楼梯深度);
VolumeBox.enabled=false;
}
我试图对该方法的主体进行注释,以允许在没有此“引用”的情况下删除BoxCollider,但仍然出现错误,因此,我猜该方法不是问题所在

此外,我还手动删除了BoxCollider,没有单击Finalize按钮触发此代码,通过右键单击inspector“Remove component”选项上的组件,错误不会出现,然后单击Finalize stairs,不会出现任何问题

正如@JoeBlow在评论中提到的,我已经检查了finalizestars方法只调用一次

我还检查了调用AddSelectionBox方法的创建过程是否在单击finalize按钮时发生

所以,拜托,我需要帮忙。这是到开发分支的链接,在这里您会发现上面提到的方法finalizeStatirs具有只删除BoxStairs脚本的代码,并且在那一刻不会抛出错误

任何关于这方面的想法或建议都将非常有用。提前谢谢

编辑: 一个最小、完整且可验证的示例:

Asset/boxstaries.cs

using UnityEngine;
using System.Collections.Generic;

namespace BoxStairsTool
{
    [ExecuteInEditMode]
    [SelectionBase]
    public sealed class BoxStairs : MonoBehaviour
    {
        private GameObject Root;

        private void Start ()
        {
            Root = this.gameObject;
            this.AddSelectionBox();
        }

        private void AddSelectionBox()
        {
            BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();

            if (VolumeBox == null)
            {
                VolumeBox = Root.AddComponent<BoxCollider>();
            }

            VolumeBox.size = new Vector3(20, 20, 20);

            VolumeBox.enabled = false;
        }

    }
}
using UnityEngine;
using UnityEditor;

namespace BoxStairsTool
{
    [CustomEditor(typeof(BoxStairs))]
    public sealed class BoxStairsEditor : Editor
    {
        private const string DefaultName = "BoxStairs";

        [MenuItem("GameObject/3D Object/BoxStairs")]
        private static void CreateBoxStairsGO ()
        {
            GameObject BoxStairs = new GameObject(DefaultName);
            BoxStairs.AddComponent<BoxStairs>();

            if (Selection.transforms.Length == 1)
            {
                BoxStairs.transform.SetParent(Selection.transforms[0]);
                BoxStairs.transform.localPosition = new Vector3(0,0,0);
            }

            Selection.activeGameObject = BoxStairs;
            Undo.RegisterCreatedObjectUndo(BoxStairs, "Create BoxStairs");
        }

        public override void OnInspectorGUI ()
        {
            if (GUILayout.Button("Finalize stairs"))
            {
                FinalizeStairs();
            }
        }

        private void FinalizeStairs ()
        {
            Undo.SetCurrentGroupName("Finalize stairs");
            BoxStairs script = (BoxStairs)target;
            GameObject go = script.gameObject;
            BoxCollider bc = go.GetComponent<BoxCollider>();

            if (bc != null)
            {
                Undo.DestroyObjectImmediate(bc);
            }
            Undo.DestroyObjectImmediate(target);
        }
    }
}
使用UnityEngine;
使用System.Collections.Generic;
命名空间工具
{
[执行编辑模式]
[选择库]
公共密封等级箱形楼梯:单层
{
私有游戏对象根;
私有void开始()
{
Root=this.gameObject;
这个.AddSelectionBox();
}
私有void AddSelectionBox()
{
BoxCollider VolumeBox=Root.GetComponent();
if(VolumeBox==null)
{
VolumeBox=Root.AddComponent();
}
VolumeBox.size=新矢量3(20,20,20);
VolumeBox.enabled=false;
}
}
}
Asset\Editor\boxstaireditor.cs

using UnityEngine;
using System.Collections.Generic;

namespace BoxStairsTool
{
    [ExecuteInEditMode]
    [SelectionBase]
    public sealed class BoxStairs : MonoBehaviour
    {
        private GameObject Root;

        private void Start ()
        {
            Root = this.gameObject;
            this.AddSelectionBox();
        }

        private void AddSelectionBox()
        {
            BoxCollider VolumeBox = Root.GetComponent<BoxCollider>();

            if (VolumeBox == null)
            {
                VolumeBox = Root.AddComponent<BoxCollider>();
            }

            VolumeBox.size = new Vector3(20, 20, 20);

            VolumeBox.enabled = false;
        }

    }
}
using UnityEngine;
using UnityEditor;

namespace BoxStairsTool
{
    [CustomEditor(typeof(BoxStairs))]
    public sealed class BoxStairsEditor : Editor
    {
        private const string DefaultName = "BoxStairs";

        [MenuItem("GameObject/3D Object/BoxStairs")]
        private static void CreateBoxStairsGO ()
        {
            GameObject BoxStairs = new GameObject(DefaultName);
            BoxStairs.AddComponent<BoxStairs>();

            if (Selection.transforms.Length == 1)
            {
                BoxStairs.transform.SetParent(Selection.transforms[0]);
                BoxStairs.transform.localPosition = new Vector3(0,0,0);
            }

            Selection.activeGameObject = BoxStairs;
            Undo.RegisterCreatedObjectUndo(BoxStairs, "Create BoxStairs");
        }

        public override void OnInspectorGUI ()
        {
            if (GUILayout.Button("Finalize stairs"))
            {
                FinalizeStairs();
            }
        }

        private void FinalizeStairs ()
        {
            Undo.SetCurrentGroupName("Finalize stairs");
            BoxStairs script = (BoxStairs)target;
            GameObject go = script.gameObject;
            BoxCollider bc = go.GetComponent<BoxCollider>();

            if (bc != null)
            {
                Undo.DestroyObjectImmediate(bc);
            }
            Undo.DestroyObjectImmediate(target);
        }
    }
}
使用UnityEngine;
使用UnityEditor;
命名空间工具
{
[自定义编辑器(类型(BoxStairs))]
公共密封类BoxStairEditor:编辑器
{
private const string DefaultName=“BoxStairs”;
[MenuItem(“游戏对象/3D对象/BoxStairs”)]
私有静态void CreateBoxStairsGO()
{
GameObject BoxStairs=新游戏对象(默认名称);
AddComponent();
if(Selection.transforms.Length==1)
{
BoxStairs.transform.SetParent(Selection.transforms[0]);
boxstaries.transform.localPosition=新向量3(0,0,0);
}
Selection.activeGameObject=BoxStairs;
Undo.RegisterCreatedObjectUndo(BoxStairs,“创建BoxStairs”);
}
InspectorGUI()上的公共覆盖无效
{
if(GUILayout.按钮(“完成楼梯”))
{
最后定案();
}
}
私有资产()
{
撤销.SetCurrentGroupName(“完成楼梯”);
BoxStairs脚本=(BoxStairs)目标;
GameObject go=script.GameObject;
BoxCollider bc=go.GetComponent();
if(bc!=null)
{
撤销、销毁客观媒体(bc);
}
撤消。销毁Objectimmediate(目标);
}
}
}
分析 我是一名程序员,所以我只是通过调试来发现问题(在我看来:D)

MissingReferenceException:类型为“BoxCollider”的对象已被销毁,但您仍在尝试访问它。
您的脚本应该检查它是否为空,或者您不应该销毁该对象。
UnityEditor.Editor.IsEnabled()(位于C:/buildslave/unity/build/Editor/Mono/Inspector/Editor.cs:590)

当代码试图在Unity3D.Object被销毁后访问它时,会发生MissingReferenceException

让我们研究一下
UnityEditor.Editor.IsEnabled()
的反编译代码

@object
从中分配一个数组,其中包含所有被检查的对象。在您的情况下,此数组中应该只有一个目标对象-BoxCollider组件

总之,检查员未能访问目标对象(我的意思是