【问题标题】:Constructor with an array of subclasses of an abstract class as a parameter以抽象类的子类数组作为参数的构造函数
【发布时间】:2009-12-13 00:33:51
【问题描述】:

我正在开发一款游戏的玩家库存系统。

我有一个结构 Slot,它有一个 List 集合,表示其中允许哪些类型的项目。抽象类 Loot 是所有可抢劫物品的子类 - 即:将是 Slot 结构的有效内容值。

我想表达的是,Slot 可以限制它可以包含的 Loot 子类。例如,如果 Slot 代表一个弹药容器,我希望它只包含作为弹药容器的 Loot 子类,例如“Quivers”和“Shot Pouches”(这将子类 Container 沿线某处)。

战利品类

public abstract class Loot : GameEntity, ILootable
{
    public int MaxUnitsPerStack { get; set; }
    public int MaxUnitsCarriable { get; set; }
    public int MaxUnitsOwnable { get; set; }

    public void Stack() { }
    public void Split() { }
    public void Scrap() { }
}

容器类

public abstract class Container : Loot
{
    public List<Slot> Slots { get; set; }

    public Container(int slots)
    {
        this.Slots = new List<Slot>(slots);
    }
}

插槽结构

public struct Slot
{
    public Loot Content;
    public int Count;
    public List<Loot> ExclusiveLootTypes;

    public Slot(Loot[] exclusiveLootTypes)
    {
        this.Content = null;
        this.Count = 0;

        List<Loot> newList;
        if (exclusiveLootTypes.Count() > 0)
        {
            newList = new List<Loot>(exclusiveLootTypes.Count());
            foreach (Loot l in exclusiveLootTypes)
            {
                newList.Add(l);
            }
        }
        else { newList = new List<Loot>(); }
        this.ExclusiveLootTypes = newList;
    }
}

玩家库存

public struct PlayerInventory
{
    static Dictionary<Slot, string> Slots;

    static void Main()
    {
        Slots = new Dictionary<Slot, string>();

        /* Add a bunch of slots */
        Slots.Add(new Slot(/* I don't know the
                              syntax for this:
                              Quiver, Backpack */), "Backpack"); // Container
    }

}

我不知道如何在 PlayerInventory 类的 Main 方法中的 Slot 构造函数调用中为 Loot 子类提供参数。

我希望这很清楚。提前致谢。

编辑

我能够使用 David Sieler 的方法和一些反射解决这个问题(我的意思是让它编译)。

插槽结构


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

    public struct Slot
    {
        private Loot _content;
        private int _count;
        public List ExclusiveLootTypes;

        public Loot Content
        {
            get { return _content; }
            private set
            {
                if ((ExclusiveLootTypes.Contains(value.GetType())) && (value.GetType().IsSubclassOf(Type.GetType("Loot"))))
                {
                    _content = value;
                }
            }
        }

        public int Count
        {
            get { return _count; }
            set { _count = value; }
        }

        public Slot(params Type[] exclusiveLootTypes)
        {
            this._content = null;
            this._count = 0;

            List newList;
            if (exclusiveLootTypes.Count() > 0)
            {
                newList = new List(exclusiveLootTypes.Count());
                foreach (Type l in exclusiveLootTypes)
                {
                    newList.Add(l);
                }
            }
            else { newList = new List(); }
            this.ExclusiveLootTypes = newList;
        }
    }

PlayerInventory 调用 Slot 构造函数


Slots.Add(new Slot(typeof(Backpack)));

再次感谢大家的讨论。

【问题讨论】:

  • 只考虑了一天,Loot 实例代表了一种战利品。插槽本身有一个 Count 属性,表示它包含多少它所持有的战利品。我完全希望改变这个十几次,但这就是它目前的工作方式。不错的 TES 参考 :)
  • 对不起,我删除了询问Loot 实例是否代表一种战利品或实际战利品的评论,因为我忘记了我在写它时的想法。因此,您似乎只需将可能的战利品类型传递给Slot 构造函数,如@Anon 的答案所示,尽管可能有很多类型的战利品可以放置在背包。你有没有想过一个界面可以让各种战利品实现可以放在背包里?
  • 嗯,ExclusiveLootTypes 列表代表了对插槽内容的一组约束,而不是可能的内容范围。如果该列表有任何条目,则该插槽只能包含列表中类型的项目。但是,如果列表为空,则它可以包含任何内容。我还没有写出那个例程,但这就是我的想法。所有的战利品子类都可以放在一个背包里——这是让它们“战利品”的原因之一。
  • 但是你不能把魔神短剑放在箭袋里。 ... List&lt;Loot&gt; 看起来很像一个可能是插槽内容的战利品类型列表,不是吗?
  • 确实如此。你认为这是我可以通过对该属性进行适当评论来解决的问题吗?还是它表明了一些更根本的缺陷?

标签: c# constructor types constraints subclassing


【解决方案1】:

您可能会发现在 Slot 构造函数的定义中使用 params 更容易:

Slot(params Loot[] exclusiveLootTypes)

这可以让你这样称呼它:

new Slot(lootItem1, lootItem2, lootItem2 /*...etc*/);

否则,您需要创建一个数组并将其传入。

【讨论】:

  • 我希望以这种方式处理它,但这仅允许我使用实例,而不是类型。上面的 new Slot(lootItem1...) 将传递现有实例。我想传递类型,例如:
     new Slot(Quiver, ShotPouch); 
    其中 Quiver 和 ShotPouch 将是 Loot 的子类。
【解决方案2】:

听起来您的对象设计需要稍作调整。

如果战利品的类型也是接口呢,例如,所有弹药战利品都继承自 IAmmoContainer。

然后你可以传入 IAmmoContainer 类型来限制插槽。

public class Quiver : Container, IAmmoContainer
public class ShotPouch : Container, IAmmoContainer
// ...
new Slot(typeof(IAmmoContainer))

编辑

根据 cmets 中的讨论,我将如何设计这个系统。

Loot 类很好。它代表了战利品等级的基础。

然后您为项目可以占用的“槽”定义接口。例如:

public class LongSword : Loot, IRightHandItem
public class ShortSword : Loot, IRightHandItem, ILeftHandItem

然后,PlayerInventory 类将“插槽”作为属性,限制为适当的类型。

public class PlayerInventory
{
    public List<IRightHandItem> RightHandSlot { get; private set; }
    public List<ILeftHandItem> LeftHandSlot { get; private set; }
    // etc...
}

【讨论】:

  • Slots.Add(new Slot(IAmmoBag), "Backpack");给出错误:“参数'1':无法从'System.Type'转换为(命名空间).Loot[]'。
  • 好吧,现在我真的很困惑。所以你的插槽已经包含了它可以包含的类型的实例?您是否尝试限制添加到插槽的类型或使用类型预初始化插槽?
  • 最初 - 在这一点上 - 不,插槽不包含任何内容(它的 Content 变量当前持有 Loot 类型 == null。)我想要做的是说如果有任何项目在 List ExclusiveLootTypes 中,然后插槽将运行验证(当我对其进行编码时)以确保 Content 变量仅接收子类 List ExclusiveLootTypes 中的类型之一的项目。所以,我想创建 Slot,并将 Loot 的一些子类传递给它,然后它将这些类型添加到 List ExclusiveLootTypes。
  • 澄清一下,我不想将类的传递实例传递给 Slot,我想传递抽象类 Loot 的子类。然后,插槽将确保其 Content 变量仅由 List ExclusiveLootTypes 中列出的子类的实例填充。
  • @your 编辑:我不认为这代表了我想要完成的事情。在这种方法中,PlayerInventory 将有一个容器 (List RightHandSlot),它可以同时容纳任意数量的,例如,LongSwords。您的 RightHand “插槽”版本更像是一个包。我将 Slot 定义为只能容纳一件物品的容器——无论是袋子、剑还是其他物品。它可以容纳的一件物品可以受其类型的限制。所以 RightHand 插槽只能容纳一项;该项目的 TYPE - 它是 Loot 的哪个子类,在 Slot 的 ExclusiveLootType 列表中定义。
【解决方案3】:

一种方法是将Type 对象的数组传递给 Slot 构造函数:

public Slot(Type[] exclusiveLootTypes) {
    // be sure and check that each Type is a subtype of Loot!
}

// Construction looks like:
new Slot(new[] {GetType(AmmoContainer), GetType(GemContainer) /* or whatever */});

然后为Content 编写一个属性设置器,检查分配对象的类型,如果该类型不包含在 ExclusiveLootTypes 中,则发出某种错误信号。

【讨论】:

    【解决方案4】:

    结合之前使用参数的建议,您可以使用 LINQ 扩展一步将参数转换为列表:

    public Slot(params Type[] exclusiveLootTypes)
    {
        this.Content = null;
        this.Count = 0;
    
        this.ExclusiveLootTypes = exclusiveLootTypes.ToList();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-02
      • 1970-01-01
      • 2019-05-12
      • 1970-01-01
      • 1970-01-01
      • 2015-03-20
      • 2010-11-26
      相关资源
      最近更新 更多