带有超类输入的通用方法中访问的子类属性 [英] subclass properties accessed in generic method with superclass input

查看:52
本文介绍了带有超类输入的通用方法中访问的子类属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想建立一个库存/设备系统来与我的物品系统交互.我的项目系统是一个基于共享属性的继承类系统.

I want to make an inventory/equipment system to interface with my item system. My item system is an inherited class system based around shared properties.

我将类型存储在枚举中,并为项目赋予一个枚举值.

I store types in enums and give the items an enum value.

我的继承结构:

Item {
  Equippable {
    Armor {Chest, Head}
    Weapon {Melee, Ranged}
  }
}

我让每个subType在其父类中定义一个枚举变量,因此Chest将在带有该类型的显式基本构造函数调用中定义armourTypes枚举.

I have each subType define an enum variable in its parent class, so Chest would define the armorTypes enum in an explicit base constructor call with the type.

例如

public enum armorTypes {Chest, Helmet}

public class Armor : Equippable
{
    armorTypes armorType;

    public Armor(armorTypes at) : base(equippableTypes.Armor) 
    {
        armorType = at;
    }
}

public class Chest : Armor 
{
    int defense = 10;

    public Chest() : base(armorTypes.Chest) {}
}

public class Helmet : Armor 
{
    int defense = 5;

    public Helmet() : base(armorTypes.Helmet) {}
}

在清单"类中,这些项目为空白版本.

In my Inventory class I have blank versions of these items.

Inventory{
  public Chest chestSlot;
  public Helmet helmetSlot;
  public Melee meleeSlot;
  public Ranged rangedSlot;
}

我想根据它们的属性比较两个插槽中的对象.

I want to compare the objects in the two slots based on their properties.

void Compare(Item item) 
{
  switch((item as Armor).armorType)
  {
      case armorTypes.Chest :
        Console.WriteLine((item as Chest).defense + " or " + chestSlot.defense);
        break;
      case armorTypes.Helmet :
        Console.WriteLine((item as Helmet).defense + " or " + helmetSlot.defense);
        break;
  }
}

但是,当我使用as关键字进行投射时,我会丢失实例吗?

However, when I cast it using the as keyword, somehow I lose my instance?

而且,因为我需要访问item.armorType,所以我无法封装Armor,可以吗?

Also, as I need to access item.armorType I cannot encapsulate Armor, can I?

推荐答案

这就是我要实现的方式. 首先,让基类定义基本的比较方法:

This is how I'd implement this. First of all, let the base class define basic comparison methods:

abstract class Item 
{
    // these methods define base comparison operations;
    // by default, items are not comparable;
    public virtual bool CanCompareWith(Item item)
    {
        return false;
    }

    // since we don't know all possible item properties,
    // this method hasn't implementation
    public abstract void CompareWith(Item item);
}

接下来,我们必须定义一些默认设备.护甲:

Next, we must define some default equipment. Armor:

abstract class Equippable : Item {}    

abstract class Armor : Equippable
{
    // every armor has a Defence property
    public abstract int Defence { get; }

    // the base comparison logic of two armors
    public override void CompareWith(Item item)
    {
        Console.WriteLine("{0} or {1}", ((Armor)item).Defence, this.Defence);
    }
}

class Chest : Armor
{
    // if you want for chests to be comared with chests only:
    public override bool CanCompareWith(Item item)
    {
        return item is Chest;
    }

    public override int Defence
    {
        get { return 10; }
    }
}

class Helmet : Armor
{
    public override bool CanCompareWith(Item item)
    {
        return item is Helmet;
    }

    public override int Defence
    {
        get { return 5; }
    }
}

武器:

abstract class Weapon : Equippable
{
    // every weapon has Attack property
    public abstract int Attack { get; }

    // the base comparison logc of two weapons
    public override void CompareWith(Item item)
    {
        Console.WriteLine("{0} or {1}", ((Weapon)item).Attack, this.Attack);
    }
}

class Melee : Weapon
{
    public override bool CanCompareWith(Item item)
    {
        return item is Melee;
    }

    public override int Attack
    {
        get { return 20; }
    }
}

class Ranged : Weapon
{
    public override bool CanCompareWith(Item item)
    {
        return item is Ranged;
    }

    public override int Attack
    {
        get { return 25; }
    }
}

请注意,这里没有任何枚举.这是因为类型本身(例如ChestHelmet等)定义了具体项目所属的位置.枚举在这里只是多余的.

Note, that there's no any enums here. This is because the type itself (e.g., Chest, Helmet, etc.) defines, where concrete item belongs to. Enum is just superfluous here.

这是库存:

class Inventory
{
    // this is inventory storage;
    // collection allows the storage to be extended later, or be displayed at once
    // (e.g., some ShowAllInventory method)
    private readonly List<Item> inventoryItems;

    public Inventory()
    {
        inventoryItems = new List<Item>
        {
            // some predefined inventory slots with default inventory items
            new Chest(),
            new Helmet(),
            new Melee(),
            new Ranged()
        };
    }

    // these properties are required, if you want to access predefined 
    // inventory slots in strongly-typed manner; they are NOT required for comparison
    public Chest ChestSlot
    {
        get { return (Chest)inventoryItems[0]; }
        set { inventoryItems[0] = value; }
    }

    public Helmet HelmetSlot
    {
        get { return (Helmet)inventoryItems[1]; }
        set { inventoryItems[1] = value; }
    }

    public Melee MeleeSlot
    {
        get { return (Melee)inventoryItems[2]; }
        set { inventoryItems[2] = value; }
    }

    public Ranged RangedSlot
    {
        get { return (Ranged)inventoryItems[3]; }
        set { inventoryItems[3] = value; }
    }

    // The comparison.
    public void Compare(Item newItem)
    {
        foreach (var item in inventoryItems)
        {
            if (item.CanCompareWith(newItem))
            {
                item.CompareWith(newItem);
            }
        }
    }
}

请注意,内部库存使用集合来存储其项目.这样就可以对项目执行批处理操作(如比较,在Compare方法中实现).

Note, that internally inventory uses a collection to store its items. This allow to perform batch operations with items (like comparison, implemented in Compare method).

现在,让我们定义一些新的物品类型并测试我们的库存:

Now, let's define some new types of items and test our inventory:

class SuperHelmet : Helmet
{
    public override int Defence
    {
        get { return 50; }
    }
}

class SuperMelee : Melee
{
    public override int Attack
    {
        get { return 200; }
    }
}

测试:

        var inventory = new Inventory();
        var superHelmet = new SuperHelmet();
        var superMeele = new SuperMelee();

        inventory.Compare(superHelmet);
        inventory.Compare(superMeele);

这篇关于带有超类输入的通用方法中访问的子类属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆