C#检查对象是否是父对象的投射子对象。

问题描述 投票:0回答:1

我无法更好地解释这个问题,但我会给你一个我的例子。

我有一个叫做 "物品 "的类,物品有一个继承它的子类,叫做 "武器",而武器有一个子类,叫做 "射程武器"

现在,我的玩家可以随意交换和使用物品,但由于都是物品,而我又不找错误,所以玩家装备的所有物品都显示为Item类。所以,如果我装备了一个范围武器,比如说枪,在我的玩家脚本中,它仍然会被认为是一个Item,我只能访问Item所具有的属性,而不能访问RangedWeapon的附加属性。我的问题是,如果我有一个Item对象,我如何检查它最初是武器还是RangedWeapon?

如果有什么不清楚的地方请问我,我会进一步解释。

感谢大家的意见:)

EDIT

代码示例。

假设我有一个叫枪的RangedWeapon对象。

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

在我的玩家脚本中,我有一个Item值来存储当前持有的物品。

//Some stuff above

private Item heldItem;

//etc

每当我装备一个物品时,该物品就会被存储在 "hold住的物品 "变量中。 所以如果我装备了枪,就会发生这种情况。

heldItem = gun;

现在这段代码是有效的,因为枪是RangedWeapon,而RangedWeapon继承自Item,但是如果我不知道我装备的是什么物品,以及它最初是物品,武器还是RangedWeapon呢?我如何通过hold住Item来检索它的原始类型?

例如:如果我可以做这样的事情(这完全是一个伪代码,为了例子的缘故)

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

希望我说的更清楚:)

c# unity3d inheritance multiple-inheritance
1个回答
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. 此外,手枪使用基类实现的 FireColorRangedWeapon 实现了它自己的颜色。

enter image description here


0
投票

:

这个问题已经由@RufusL回答了,我只是把它作为一个答案而不是一个评论贴出来,以便更容易看到。

解决办法是简单地使用 is 运营商。

我引用。

 if (item is RangedWeapon) { RangedWeapon rw = (RangedWeapon) item; //
 access RangedWeapon properties of rw here }
© www.soinside.com 2019 - 2024. All rights reserved.