【问题标题】:Can I use a main class object as a parameter to find the subclass object?我可以使用主类对象作为参数来查找子类对象吗?
【发布时间】:2018-02-12 14:13:26
【问题描述】:

我在编码方面还是个新手,所以我想知道这是否/如何工作?

//a class with armor with subclasses to say what part of the body it go's
public class Armor
{
    //stuff that applies to all armor          
}
public class HeadArmor : Armor
{
    //stuff for HeadPieces only
}
public class ChestArmor : Armor
{
}
 //etc

//the class that stores what  armor is equiped
public class MainCharacterEquipment
{
    //the class of my maincharacter
    public MainCharacter HeroEquipment { get; set; }

    public HeadArmor HeadSlot { get; set; }
    public ChestArmor ChestSlot { get; set; }
    //etc
    //a constructor that sets all to null

    public void EquipArmor(Armor armor)
    {
        if (armor is HeadArmor)
        {
            HeadSlot = armor; //compile error
        }
        if (armor is ChestArmor)
        {
            ChestSlot = armor; //compile error -> Missing a cast?
        }
        //etc
    }
}

如果我这样做,它会询问我是否缺少演员表。 从这个论坛上的阅读看来,子类是主类的一种 但反之则不然。

为了解决这个问题,我可以为每个盔甲子类创建一个方法。 我不会使用(Armor Armor)作为参数,而是使用(HeadArmor headArmor),(ChestArmor chestArmor)等...... 但这似乎很乏味。 我还读到 typeof() 和 is 之间有区别,但我也不太明白。 最好我只是将对象装甲投射到它的子类中。当然,if 函数应该检查它是否已经是子类(如果有意义的话)

ps:实际上没有 Armor 对象的实例。只有子类的对象被实例化。 (有没有关系)

【问题讨论】:

  • try if ( armor is HeadArmor hArmor ) { HeadSlot = hArmor; } ... 如果类型匹配,这也会进行强制转换。当然,还有更多解决方案……但从简单开始。
  • @Korosevar 你是在为 Unity 开发这些东西吗?如果是这样,模式匹配将不起作用
  • @Fildor 我得到错误:hArmor 在当前上下文中不存在
  • 为什么不把 HeadSlot 和 ChestSlot 都做成 Armor 类型呢?这就是多态性大放异彩的时候。
  • 那是哪个平台? .Net 框架 4.7 ? .Net 核心?统一? ...这可能会排除一些解决方案...

标签: c# class casting type-conversion


【解决方案1】:

您需要在分配时指定相同的演员表。一旦初始检查通过,编译器就不会通过if 语句携带信息。

在您的代码中:

if (armor is HeadArmor) // The compiler verifies this is HeadArmor
{
    // The compiler does not carry the information forward.
    // It has no way of knowing, on this line, that armor is still HeadArmor.
    // For all it knows, armor  could be ChestArmor which would be invalid.
    HeadArmor = armor; 
}

要修复错误,您需要按如下方式更新代码:

if (armor is HeadArmor)
{
    HeadArmor = (HeadArmor)armor; // Lets the compiler know this is HeadArmor.
}

另一种选择是使用as 尝试找出正确的选择。

var headArmor = armor as HeadArmor;
if (headArmor != null)
{
    HeadArmor = headArmor;
}

【讨论】:

  • 修复了它。而且看起来很干净。 (HeadArmor) 盔甲是铸件吗?
  • 是的,没错。 (HeadArmor)armor 告诉代码将该盔甲解释为 HeadArmor,即使编译器知道它的类型是盔甲。
【解决方案2】:

我建议使用访客模式:

public abstract class Armor
{
    public abstract void Equip( MainCharacterEquipment mce );
}
public class HeadArmor : Armor
{
    public override void Equip( MainCharacterEquipment mce )
    {
         mce.HeadSlot=this;
    }
}
public class ChestArmor : Armor
{
    public override void Equip( MainCharacterEquipment mce )
    {
         mce.ChestSlot=this;
    }
}

那么您的 MainCharacterEquipment 代码归结为:

public void EquipArmor(Armor armor)
{
     armor.Equip(this); 
}

这消除了“if-else”,如果您以后选择添加更多类型的盔甲和插槽,则无需触摸该代码。只需添加另一个 XXXXArmor 类,它就会进入正确的插槽。

【讨论】:

  • 是否有可能必须在抽象类中使用 public virtual void?我在类似的情况下得到“不能声明一个身体,因为它是抽象的”
猜你喜欢
  • 1970-01-01
  • 2016-06-17
  • 2018-08-04
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
相关资源
最近更新 更多