在 c# 中抽象自动转换 类

Auto casting abstracted classes in c#

我正在努力寻找一种在 C# 中制作项目、列表和数据库的简化方法,虽然一切正常,但我需要将结果输出。

到目前为止我有以下内容

namespace Game.Database
{

    public abstract class DatabaseItem : ScriptableObject
    {

    }

    public class DatabaseList : ScriptableObject
    {
        public List<DatabaseItem> items;
    }

    public class ShipClass : ScriptableObject
    {
        public string shipClassID;
        new public string name;
    }

    public class Ship : DatabaseItem
    {
        public string shipID;
        new public string name;
        public ScriptableObject shipClass;
    }

}

public class Database : MonoBehaviour
{
    public List<DatabaseList> lists;

     void Start()
    {
        Ship ship = (Ship)lists[0].items[0];
        Debug.Log(shipClass.shipID);
        ShipClass shipClass = (ShipClass)ship.shipClass;
        Debug.Log(shipClass.shipClassID);
    }
}

请记住,这是一个统一项目,因此这些项目正在实例化并通过 UI 分配数据。

如您所见,我有一个项目摘要,将有多种类型的项目和多个列表。我试图避免为我的列表制作多个 class',每种类型的项目一个。所以我从 DatabaseItem 中提取了我的项目,这样我就可以在我的 DatabaseList 中存储 DatabaseItem 的列表。然而,这意味着在读出我的数据时,我需要将其转换回 Ship class.

虽然这对于简单的实施来说还不错,但在生产中,这些将嵌套,需要多次转换才能获得所需的数据。

不幸的是,我发现自己缺乏真正 google 问题所需的 c# 词汇。查看 Microsoft 用户定义的转换运算符及其示例即使是我想要实现的也是没有意义的。

编辑 - 问题是如果不访问数据,就像我能做到的那样,它必须分解数据的每个级别,因为最终这将非常通用地用于所有游戏数据并且非常嵌套,因此必须将每个级别都转换为能够分解它是我试图避免的。

像这样的东西应该是一个很好的起点。具体实现需要根据您的游戏需求进行调整。有关泛型类型的更多信息 here.

public abstract class Item: ScriptableObject
{
   public string name;

   public abstract void Use();
}

public class Ship: Item
{
   public string id;

   public override void Use()
   {
      Debug.Log($"I'm a Ship, my name is {name}, my id is {id}.");
   }
}

public class Plane: Item
{
   public float speed;

   public override void Use()
   {
      Debug.Log($"I'm a Plane, my name is {name}, my speed is {speed}.");
   }
}

public class Database: ScriptableObject
{
   [SerializeField] private List<Item> items;

   public T GetItem<T>(int i) { return (T) items[i]; }

   public Item AddItem() { ... }
   public Item RemoveItem() { ... }
}

public class DatabaseHolder: MonoBehaviour
{
   public Database database;

   void Start()
   {
      Ship ship = database.GetItem<Ship>(0);

      // Or...

      Plane plane = database.GetItem<Plane>(1);
   }
}

一种方法是在每种类型的项目上公开一个方法来写出数据,这样调用代码就不需要知道底层细节。

请参阅下文,了解如何避免进行任何转换。

namespace Game.Database
{

    public abstract class DatabaseItem : ScriptableObject
    {
         public abstract void WriteOut();
    }

    public class DatabaseList : ScriptableObject
    {
        public List<DatabaseItem> items;
    }

    public class Ship : DatabaseItem
    {
        public string shipID;
        new public string name;

        public override void WriteOut()
        {
            Debug.Log(shipID);
        }
    }

}

public class Database : MonoBehaviour
{
    public List<DatabaseList> lists;

     void Start()
     {
        lists[0].items[0].WriteOut();
     }
}

这样您就可以让每个项目类型处理自己的写出。我建议仔细考虑您的 API.

为了更加 SOLID 和干净,您可以使用依赖注入并将写入注入到类型中,请参见下面的另一个示例。

这样做的好处是允许多种类型使用相同的编写器代码,并且您还可以让您的 class 遵循单一职责原则。

namespace Game.Database
{
    public interface IWriter
    {
        void Write(string output);
    }

    public class ConsoleWriter: IWriter
    {
        public void Write(string output)
        {
             Debug.Log(output);
        }
    }

    public abstract class DatabaseItem : ScriptableObject
    {
         public abstract void WriteOut();
    }

    public class DatabaseList : ScriptableObject
    {
        public List<DatabaseItem> items;
    }

    public class Ship : DatabaseItem
    {
        private IWriter _writer;

        public Ship(IWriter writer)
        {
            _writer = writer;
        }

        public string shipID;
        new public string name;

        public override void WriteOut()
        {
            _writer.Write(shipID);
        }
    }
}

public class Database : MonoBehaviour
{
    public List<DatabaseList> lists;

     void Start()
     {
        lists[0].items[0].WriteOut();
     }
}