繁体   English   中英

泛型和继承:将泛型与基类及其子类一起使用

[英]Generics and Inheritance: Using generics with a base-class and its sub-classes

在过去的几天中,我一直在尝试开发UI项目拖放系统,并使其尽可能灵活(尽管它与我的问题并不完全相关),但正在使用Unity 3D进行开发。 在准确解释问题所在之前,这里是代码:

public class ItemHandler<ItemType> : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IHoverHandler where ItemType : Item {

     public ItemType item { get; protected set; }

     ...
}

public abstract class SlotHandler<ItemType> : MonoBehaviour, IDropHandler where ItemType : Item {

    ...

    public ItemHandler<ItemType> itemHandler { get; protected set; }

    ...

    public void OnDrop(PointerEventData eventData) {

        // Retrieve the slots
        SlotHandler<Item> originalSlotHandler = ItemManager.draggedItemParent.GetComponent<SlotHandler<Item>>();
        SlotHandler<ItemType> destinationSlotHandler = this;

        // Retrieve the handlers from their items
        ItemHandler<Item> originalItemHandler = originalSlotHandler.itemObject != null ? originalSlotHandler.itemObject.GetComponent<ItemHandler<Item>>() : null;
        ItemHandler<ItemType> destinationItemHandler = destinationSlotHandler.itemObject != null ? destinationSlotHandler.itemObject.GetComponent<ItemHandler<ItemType>>() : null;

        // Add the original item to the destination slot
        bool canAddToDestination = originalSlotHandler is SlotHandler<ItemType> || originalSlotHandler is SlotHandler<Item>;
        bool canRemoveFromOrigin = originalSlotHandler is SlotHandler<ItemType> || destinationSlotHandler is SlotHandler<Item>;

        // Swap the items
        if(canAddToDestination == true && canRemoveFromOrigin == true) {

            // Remove the old items
            originalSlotHandler.RemoveItem();
            destinationSlotHandler.RemoveItem();

            // Add the new items
            originalSlotHandler.AddItem(destinationItemHandler);
            destinationSlotHandler.AddItem(originalItemHandler);

            ...
        }

        ...
    }

    public virtual void AddItem(ItemHandler<ItemType> itemHandler) {

        this.itemHandler = itemHandler;
    }
}

其背后的想法是让给定类型的ItemHandler(例如ItemHandler <Gem>,ItemHandler <Weapon>等),然后只允许将它们放入相同类型或相同基本类型的SlotHandlers中。

  • ItemHandler <Gem>进入SlotHandler <Gem>和SlotHandler <Item>。
  • ItemHandler <武器>进入SlotHandler <武器>和SlotHandler <Item>。

我尝试以这种方式进行操作,因为我想限制我可以放置特定项目的插槽。

问题来自以下事实:我必须考虑特定类型的插槽SlotHandler <Item>(您在代码段中看到的Item类,它是所有Items的基类)。 库存槽应能够容纳每种类型的物品。

现在,由于ItemHandler <Gem>不是ItemHandler <Item>的子类(或Item的任何其他派生类型),因此将不起作用。 现在您可能会说为什么不只存储Item而不存储Generic ItemType? 但我的想法是派生SlotHandler并在每个子类中具有特定的行为(将项目放入不同类型的插槽应做不同的事情)。

我想我理解为什么这样做无法按我尝试的方式工作,但找不到适合自己的解决方案,因此我想尝试寻求帮助。 抱歉,如果我对问题尚不十分清楚,请告诉我是否应该解决一些问题。

在此先感谢您为解决我的问题提供的任何帮助!

在我看来,尽管您需要跟踪类型,但您真正需要的只是记录每个项目的父母(和他们的父母)的类型。 与其在编程意义上使用类型本身,不如不只是使用字符串标签并在基类中为该项目的有效类型的层次结构创建列表。 这样,您可以拥有复杂的连接和组织,只需要将单个字符串与列表进行比较以查看其是否有效。

using UnityEngine;
using System.Collections.Generic;

public class Item {

  public List<string> validInvTypes = new List<string>();

  //...
}

public class Gem : Item {

  //...
}

public class Ruby : Gem {

  public Ruby()
  {
    validInvTypes.Add("Ruby");
    validInvTypes.Add("Gem");
    validInvTypes.Add("Item");
  }

  //...
}

public abstract class SlotHandler<ItemType> : MonoBehaviour, IDropHandler where ItemType : Item {

  //...

  public void OnDrop(PointerEventData eventData)
  {
    //...

    //string currentInvSlot
    //Item droppedItem

    if (droppedItem.validInvTypes.Contains(currentInvSlot))
      // Swap the items...
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM