简体   繁体   English

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

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

I've been trying to develop an UI item dragging and dropping system for the past few days and make it as flexible as possible (it's being developed using Unity 3D although that's not exactly relevant to my problem). 在过去的几天中,我一直在尝试开发UI项目拖放系统,并使其尽可能灵活(尽管它与我的问题并不完全相关),但正在使用Unity 3D进行开发。 Here's the code before I get to explaining exactly what the issue is: 在准确解释问题所在之前,这里是代码:

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;
    }
}

The idea behind this is to have ItemHandler of a given type (eg ItemHandler< Gem >, ItemHandler< Weapon > etc.) and then only allow them to be dropped into SlotHandlers of the same type OR of the same base type. 其背后的想法是让给定类型的ItemHandler(例如ItemHandler <Gem>,ItemHandler <Weapon>等),然后只允许将它们放入相同类型或相同基本类型的SlotHandlers中。

  • ItemHandler< Gem > goes into SlotHandler< Gem > and SlotHandler< Item >. ItemHandler <Gem>进入SlotHandler <Gem>和SlotHandler <Item>。
  • ItemHandler< Weapon > goes into SlotHandler< Weapon > and SlotHandler< Item >. ItemHandler <武器>进入SlotHandler <武器>和SlotHandler <Item>。

I tried doing things this way because I want to limit in which slots I'm able to drop specific items. 我尝试以这种方式进行操作,因为我想限制我可以放置特定项目的插槽。

The problem comes from the fact that I have to take into account a specific type of slot, SlotHandler< Item > (the Item class you see in the code snippet which is the base class for all Items). 问题来自以下事实:我必须考虑特定类型的插槽SlotHandler <Item>(您在代码段中看到的Item类,它是所有Items的基类)。 The inventory slots should be able to hold every type of item. 库存槽应能够容纳每种类型的物品。

Now, since ItemHandler< Gem > isn't a subclass of ItemHandler< Item > (or any other derived type of Item) this won't work. 现在,由于ItemHandler <Gem>不是ItemHandler <Item>的子类(或Item的任何其他派生类型),因此将不起作用。 Now you might say why not just store Item instead of storing a Generic ItemType? 现在您可能会说为什么不只存储Item而不存储Generic ItemType? I would but the idea here is to derive SlotHandler and have specific behaviour in each sub-class (dropping items into different types of slots should do different things). 但我的想法是派生SlotHandler并在每个子类中具有特定的行为(将项目放入不同类型的插槽应做不同的事情)。

I think I understand why this won't work the way I'm trying to do it but I can't find a solution I feel comfortable with so I thought I'd try and ask for some help. 我想我理解为什么这样做无法按我尝试的方式工作,但找不到适合自己的解决方案,因此我想尝试寻求帮助。 Sorry If I'm not being clear enough with the problem, please let me know if I should clear something up. 抱歉,如果我对问题尚不十分清楚,请告诉我是否应该解决一些问题。

Thanks in advance for any help trying to solve my problem! 在此先感谢您为解决我的问题提供的任何帮助!

To me it seems that although you need to keep track of the types, all you really need is a record of the parents' type (and their parents) for each item. 在我看来,尽管您需要跟踪类型,但您真正需要的只是记录每个项目的父母(和他们的父母)的类型。 Rather than using the type itself in a programming sense why not just use a string label and create a list in the base class for the hierarchy of valid types for the item. 与其在编程意义上使用类型本身,不如不只是使用字符串标签并在基类中为该项目的有效类型的层次结构创建列表。 That way you can have complex connections and organization and only need to compare a single string to a list to see if it's valid. 这样,您可以拥有复杂的连接和组织,只需要将单个字符串与列表进行比较以查看其是否有效。

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