具有抽象类的子类数组作为参数的构造方法

时间:2009-12-13 00:33:51

标签: c# constructor types constraints subclassing

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

我有一个struct Slot ,它有一个List< Loot>表示允许哪些项目的集合。抽象类 Loot 由所有可掠夺的项子类化 - 即:将是 Slot 结构的有效内容值。

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

Loot class

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

PlayerInventory

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

再次感谢大家的讨论。

4 个答案:

答案 0 :(得分:2)

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

Slot(params Loot[] exclusiveLootTypes)

这可以让你称之为:

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

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

答案 1 :(得分:2)

听起来你的对象设计需要稍微调整一下。

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

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

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

修改

根据评论中的讨论,以下是我如何设计这个系统。

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

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

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

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

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

答案 2 :(得分:1)

一种方法是将一个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编写一个属性setter来检查指定对象的类型,如果该类型不包含在ExclusiveLootTypes中,则发出某种错误信号。

答案 3 :(得分:1)

并结合之前的建议使用params,您可以使用LINQ扩展将params转换为List一步:

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

    this.ExclusiveLootTypes = exclusiveLootTypes.ToList();
}