【问题标题】:Retrieve information about the classes implementing an interface检索有关实现接口的类的信息
【发布时间】:2017-04-21 16:34:18
【问题描述】:

我对我正在编写的代码有一些疑问,希望您能启发我或帮助我找到更好的解决方案。

我有一个 Player 类,其中包含一些 Slot 类型的成员。每个 Slot(下面的代码)都包含一个 Equippable,它是一个由特定类(如 Armor、Weapon、Shield、MagicItem)实现的接口。我需要这样做,因为我不想为每种类型的可装备项目编写 Slot 类。

class Slot{
    private Equippable item;
    public Equippable Item = > item;
    // here is constructor with default null item
    // here are some methods to occupy/free slot
}

现在让我们回到 Player 类,我在其中有一些插槽:武器插槽、盔甲插槽等。这里我需要检索有关项目的信息;例如,我需要取回护甲加成。我需要做这样的事情:

int armorBonus = armorSlot.Item.Bonus;

显然这不起作用,因为 Slot 类型中的 Item 只是一个 Equippable 并且不一定具有 Bonus 属性。所以我想到了两种解决方案:

  1. 为 Equippable 提供 Bonus 属性:我可以在 Equippable 中放置一个 Bonus 属性,该属性将由每个类实现。这样,一切都会好起来的。 虽然,我觉得这并不完全正确,因为并非所有物品都需要奖金。我将如何处理具有不需要它的项目类型的 Bonus 属性?将其保留为默认值? 这是不是很笨拙
  2. 执行强制转换:我可以通过以下显式转换来解决这种情况,但我不太习惯强制转换,所以我不确定我是否忽略了某些东西。这是继续的好方法吗?

代码如下:

Armor armor = (Armor)armorSlot.Item;
int armorBonus = armor.Bonus;

困扰我的是,我应该小心为每个插槽提供正确的项目类型(直到运行时异常我才知道),因为插槽不知道它允许包含什么类型的 Equippable。

好吧,我在写的时候想到了另一个想法,所以我把它放在这里:

  1. 告诉 Slot 它可以容纳哪个物品:这更像是对第二个解决方案的改进,而不是一个新的解决方案。我可以在 Slot 中存储一个字符串(甚至是一个枚举),告诉它它可以接受哪个项目,所以我确信我正在做正确的转换。不过,我如何检查它是否收到了正确类型的项目? 此外,我认为我应该无论如何这样做,以避免将项目分配到错误的插槽。

您对如何改进这一点有任何想法吗?

【问题讨论】:

  • 您可以编写第二个支持 Bonus 属性的接口:IHasBonus 或其他。 if (armorSlot.Item is IHasBonus) { ...。项目可以实现也可以不实现。
  • 如果这个问题似乎在这个项目的许多相关形式中出现,你可以考虑编写一个属性包接口,一切都需要支持:double bonus; if (armorSlot.Item.TryGetProperty(Props.Bonus, out bonus)) { ...
  • C# 不允许多重继承,但它允许多个接口实现(以及接口分组):public interface IEquippable { }public interface IBonusProvider { },如果您仍需要将两者都作为接口操作,您可以使用 @ 987654329@
  • 感谢双方,我会尝试这个解决方案。 @EdPlunkett:不过,我不明白你的第二条评论。
  • @Harnak 我的意思是,给他们某种内部属性字典,这样您就可以询问该项目的Bonus 属性,它要么给你价值,或者说它没有。现在你对Bonus 有这个问题;也许会有其他六个属性。这是否意味着编写六个接口,或者可能是四个(如果其中一些属性一起使用)?如果你知道 WPF,也许最好写一个从对象中获取任意属性的通用方案,有点像 WPF 中的 DependencyObjects。

标签: c# interface casting subclass


【解决方案1】:

您可以将Slot 定义为泛型类。

class Slot<T> where T : Equippable {
    // ...
}

然后您可以通过您想要的特定插槽类型在 Player 上定义某些类型的插槽。例如:

class Player {
    Slot<Armor> ArmorSlot { get; set; }
    Slot<Weapon> WeaponSlot { get; set; }
}

这样做的好处是您不需要为每个Equippable 编写一个“单独的”插槽类,但您可以强制每个插槽可以使用的特定类型的设备。

【讨论】:

  • 天啊,我喜欢这个解决方案。谢谢!只是一个小建议:我可以添加一个带有适当设置器的项目,例如public T item { get; set; }。不过,我怎样才能删除一个项目以释放​​插槽?在前面的代码中,我取消了该项目,但现在我不能这样做,因为它告诉我 T 不一定可以为空。
  • item = null?我想我不明白你在问什么。
  • 是的,我需要一个默认情况,其中插槽为空,即 Slot 中的字段T item 应该为空,直到我为其分配一个项目。
  • 好的,我明白你现在在说什么了。你可以做item = default(T);
  • 哦,好吧,这比我想象的要简单,但我不知道。谢谢! :)
猜你喜欢
  • 2016-09-30
  • 2010-11-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 1970-01-01
  • 2017-09-11
  • 2014-08-04
  • 1970-01-01
相关资源
最近更新 更多