C#检查对象是否是父对象的强制转换子代

时间:2020-05-20 17:42:38

标签: c# unity3d inheritance multiple-inheritance

我无法真正更好地解释这一点,但我将举例说明我的情况:

我有一个叫做“ Item”的类类型 Item具有继承它的子类,称为“武器” 并且Weapon有一个子类,称为“ RangedWeapon”

现在,我的玩家可以随意交换和使用物品,但是由于它们都是物品,而且我不是在寻找错误,因此玩家装备的所有物品都显示为物品类。因此,如果我在玩家脚本中装备了远程武器(例如枪支),它将仍然被视为物品,并且我将只能访问物品具有的属性,而不能访问RangedWeapon的其他属性。我的问题是,如果我有一个Item对象,如何检查它最初是武器还是RangedWeapon?

如果不清楚,请问我,我将进一步解释。

感谢您的所有评论:)

编辑

代码示例:

让我们说我有一个名为Gun的RangedWeapon对象。

RangedWeapon gun = new RangedWeapon(*parameters here*);

在我的播放器脚本中,我有一个Item值,用于存储当前持有的物品:

//Some stuff above

private Item heldItem;

//etc

每当我装备一个物品时,该物品就会存储在“ heldItem”变量中。 因此,如果我要装备枪支,那将会发生:

heldItem = gun;

现在此代码有效,因为枪支是RangedWeapon且RangedWeapon继承自Item,但是如果我不知道我装备的是什么物品,以及它最初是Item,Weapon还是RangedWeapon,该怎么办?如何通过holdItem检索其原始类型?

例如: 如果我可以做类似的事情(出于示例的考虑,这完全是伪代码)

if (typeof(heldItem) was RangedWeapon) {//stuff}
else if (typeof(heldItem) was Weapon) {//stuff}

希望我让自己变得更加清晰:)

2 个答案:

答案 0 :(得分:2)

解决此问题的另一种方法是在项目列表中使用interface而不是class。接口之所以不错,是因为它们定义了契约-保证存在的一组公共方法和属性,但是类本身定义了实现。

List<Item>的问题在于列表的所有成员都向下转换(不确定该术语是否正确)到Item,并且只有任何通用方法的基类实现将被呼叫。

通过一个接口,列表中的每个对象都保留了其特定类型的实现,因此,当调用相同的方法时,我们可以从不同类型的对象中获得不同的结果。

这里是一个例子,可能不是最好的例子,但我认为它说明了这一点:

// This interface defines the public members that we want to access from any Item
public interface IItem
{
    string Name { get; set; }
    void Click();
}

// This class may be a base class for other items, but it's *NOT* a base class for
// Weapon. Instead, Weapon will implement a common interface with other items
public class Item : IItem
{
    public string Name { get; set; } = "Item";

    public void Click()
    {
        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.WriteLine($"{Name} was selected!");
        Console.ResetColor();
    }
}

// Here we have Weapon as a base class that implements the IItem interface,
// (and contains the default implementation for sub classes)
public class Weapon : IItem
{
    public string Name { get; set; } = "Weapon";

    public void Click()
    {
        Console.ForegroundColor = FireColor;
        Console.WriteLine($"{Name} was fired!");
        Console.ResetColor();
    }

    // FireColor is protected, meaning it's only available to
    // this class and classes that derive from this class
    protected ConsoleColor FireColor { get; set; } = ConsoleColor.Red;
}

// Now we have a class that derives from the Weapon 
// base class, and changes the Name property
public class Pistol : Weapon
{
    public Pistol()
    {
        Name = "Pistol";
    }
}

// And an additional class that derives from 
// Weapon, which changes both Name and FireColor
public class RangedWeapon : Weapon
{
    public RangedWeapon()
    {
        FireColor = ConsoleColor.Yellow;
        Name = "Ranged Weapon";
    }
}

现在,当我们想要一个项目集合时,我们创建一个对象集合,这些对象实现IItem接口,而不是一个具体的具体类。这样,我们可以获得所有通用方法,但是行为来自实际的类类型:

private static void Main()
{
    // Add three unique objects that implement 'IItem' to a list
    var items = new List<IItem>
    {
        new Item(),
        new Pistol(),
        new RangedWeapon()
    };

    // Call the 'Click' method for each 'IItem' object
    items.ForEach(item => item.Click());

    GetKeyFromUser("\nDone! Press any key to exit...");
}

输出

请注意,在输出中,每个项目的颜色都不同,ItemWeapon之间的文本也不同(即"selected""fired"),并且每个项目都显示唯一的Name。另外,手枪对FireColor(红色)使用基类实现,而RangedWeapon实现它自己的颜色。

enter image description here

答案 1 :(得分:0)

注意

该问题已由@RufusL回答,我只是将其发布为答案,而不是作为评论,以使其更容易看到。

解决方案是仅使用is运算符。

我引用:

 if (item is RangedWeapon) { RangedWeapon rw = (RangedWeapon) item; //
 access RangedWeapon properties of rw here }