簡體   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