Unity - InvalidCastException в редакторе автоматически refre sh для списка объектов (который был действителен ранее) - PullRequest
0 голосов
/ 05 февраля 2020

Я работаю над менеджером проекта, который определяет сценарии, которые могут быть использованы несколькими другими проектами позже (путем расширения некоторой части для их обновления).

У меня фактически есть:

  • 2 пространства имен Foo (менеджер) и Bar (проект)
  • Оба определяют объект Символ (расширение Bar.Character от Foo.Character)
  • FooEngine находится здесь, чтобы перечислять Foo.Character (Список)
  • FooEngineEditor (определенный в пространстве имен Bar) здесь для добавления (как Foo, так и Bar Bar Character) и отображения Персонажи (и их состав)

Foo

namespace Foo
{
    [System.Serializable]
    public class Character
    {
        public int ID;
        public Character(int ID)
        {
            this.ID = ID;
        }
    }


    public class FooEngine : MonoBehaviour
    {
        public List<Foo.Character> list = new List<Foo.Character>();
    }
}

Bar

namespace Bar
{
    [System.Serializable]
    public class Character: Foo.Character
    {
        public string name;
        public MyObject(int ID, string name)
            : base (ID) {
            this.name= name;
        }
    }

    [CustomEditor(typeof(Foo.FooEngine))]
    public class FooEngineEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            Foo.FooEngine fooEngine = (Foo.FooEngine)target;

            // --- Default inspector
            DrawDefaultInspector();

            // --- Action

            int countExistig = fooEngine.list.Count;

            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Add Foo.Character"))
            {
                fooEngine.list.Add(new Foo.Character(countExistig));
            }
            if (GUILayout.Button("Add Bar"))
            {
                fooEngine.list.Add(new Bar.Character(countExistig, "abc"));
            }

            // --- Review
            for (int i = 0, l = fooEngine.list.Count; i < l; i++)
            {
                EditorGUILayout.LabelField(" - " + i + " > " + fooEngine.list.GetType());
            }
        }
    }
}

Все работает нормально, и я могу использовать скрипт Editor для добавления Foo.Character или Bar.Character в один и тот же список (и приведение работает нормально).

Но когда я сохраняю код, List повторно преобразуется в Foo.Character и создает ошибку InvalidCastException, если я пытаюсь привести Bar.Character character = (Bar.Character)fooEngine.list[0];

enter image description here

Что добавить и что? Вызывает ли переписывание списка ??

1 Ответ

1 голос
/ 05 февраля 2020

Это проблема C#. Вы не можете привести объект, созданный как экземпляр базового класса, к производному классу. Это не так, как полиморфизм разработан. Если вы создаете объект как Foo.Character, он никогда не может быть приведен к Bar.Character, который наследует его, ЕСЛИ изначально этот объект не был создан как Bar.Character, затем приведен к базовому объекту, а затем снова обратно.

Идея базового класса, который, по-видимому, является вашим вариантом использования класса Foo.Character, заключается в том, чтобы быть общим классом, из которого несколько производных, а не классом, который вы создаете (например, абстрактный класс) , Я бы сказал, что при таком сценарии нельзя создать символ Foo.Character. И поэтому все экземпляры должны быть Bar.Character или любым другим производным экземпляром базового символа.

Простое изменение этой строки

Bar.Character character = (Bar.Character)fooEngine.list[0];

на

Foo.Character character = (Foo.Character)fooEngine.list[0];

Будет скомпилировано и выполнено в соответствии с вашим примером. Он приведёт все к своему базовому классу, но вы по-прежнему будете иметь данные из оригинального Bar.Character до приведения (это будет работать только в вашем примере, но не в предложенном мной коде ниже).

Вот мои предлагаемые изменения:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo.FooEngine fooEngine = new Foo.FooEngine();
            //TODO: NO LONGER POSSIBLE fooEngine.list.Add(new Foo.Character(0));
            fooEngine.list.Add(new Bar.Character(0, "Test1"));
            fooEngine.list.Add(new Example.Character(0, "Test2"));
            Bar.Character character = (Bar.Character)fooEngine.list[0];
            Example.Character character2 = (Example.Character)fooEngine.list[1];

        }
    }
}

namespace Foo
{
    using System.Collections.Generic;

    public abstract class Character
    {
        public int ID;
    }


    public class FooEngine
    {
        public List<Foo.Character> list = new List<Foo.Character>();
    }
}

namespace Bar
{

    public class Character : Foo.Character
    {
        public string name;
        public Character(int ID, string name)
        {
            base.ID = ID;
            this.name = name;
        }
    }

}

namespace Example
{

    public class Character : Foo.Character
    {
        public string name;
        public Character(int ID, string name)
        {
            base.ID = ID;
            this.name = name;
        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...