8

我有一个角色扮演游戏的类结构,看起来像这样......

public abstract class Item
{
   public abstract string Name { get; set; }
}

public abstract class Armor : Item
{
   public override string Name { get; set; }
}

public class Helmet : Armor
{
   public override string Name { get; set; }
}

基本上,我试图强制每个派生类型包含一个“名称”属性。这是最好的方法吗?我知道我可以从 Item.Name 中删除“抽象”,然后删除 Armor 和 Helmet 中覆盖的“名称”属性。如果我这样做,代码看起来会更干净一些,但我可能会忘记在这些派生类中设置 base.Name。

有人可以帮我看看最好的方法吗?

编辑:对不起,让我再澄清一下我的问题。我想确定两件事。1)名称属性存在于所有派生类中 2)名称属性不为空或为空

我基本上想强制从 Item 派生的任何类(并且不是抽象的)具有 Name 的值。

4

7 回答 7

9

听起来您很担心初始化属性?

但我可能会忘记在这些派生类中设置 base.Name。

您可以强制设置 Name 属性的一种方法是将此设置器包含在您的基类构造函数中,如下所示:

public class MyBaseClass
{
    private string _name;

    public MyBaseClass(string name)
    {
        _name = name;
    }
}

然后从 MyBaseClass 派生的所有内容都必须满足该构造函数:

public class MyDerivedClass
{
    public MyDerivedClass(string name) : base(name)
    {

    }
}

然后你也可以使属性:

  • abstract 以确保它存在于每个具有自己实现的派生类中
  • virtual 提供一个基本实现和所有它被覆盖。

我不打算冒险上面是否是好的设计,但它可以确保所有派生类在实例化时都具有有效的名称属性。

正如其他答案所暗示的那样,另一种方法是实现一个在其基本实现中引发异常的虚拟属性。

于 2010-01-28T21:38:05.383 回答
4

只需要Name在基类中定义,不需要指定为抽象类。它仍然可以作为所有派生类中的属性使用。

public abstract class Item
{
   public string Name { get; set; }
}

public abstract class Armor : Item
{ }

public class Helmet : Armor
{ }
于 2010-01-28T21:22:26.013 回答
2

如果我这样做,代码看起来会更干净一些,但我可能会忘记在这些派生类中设置 base.Name。

然后对象的名称最终会变得很愚蠢。

更好的是,namenull. 然后,如果您忘记初始化名称但有人尝试使用它,您将得到一个异常,并且您将知道您必须修复它。

于 2010-01-28T21:25:19.967 回答
2

迈克是对的,如果您只想在所有派生对象上使用属性“名称”,则根本不需要将其标记为抽象,因为它是继承的。

如果您只想强制在创建项目时确定设置名称这一事实,您可以通过隐藏零参数构造函数并公开接受名称的构造函数来强制它。

看看这段代码:

public class Item
{
   public string Name { get; set; }

   public Item(string name)
   {
       this.Name = name;
   }

   protected Item() {}
}

public class Armor : Item
{   
   public Armor(string name) : base(name) {}
   protected Armor() {}
}

public class Helmet : Armor
{   
   public Helmet(string name) : base(name) {}
   protected Helmet() {}
}

上述定义意味着:

Helmet myHelmet = new Helmet(); //will not build
Helmet myHelmet = new Helmet("Some Fancy Helmet Name"); //will build

Armor myArmor  = new Armor (); //will not build
Armor myArmor  = new Armor ("Some Fancy Armor Name"); //will build

Item myItem = new Item (); //will not build
Item myItem = new Item("Some Fancy Item Name"); //will build

这迫使类的任何实例都必须在创建时定义名称。无论如何,一种可能的解决方案...

于 2010-01-28T21:27:24.437 回答
0

将使 Name 成为虚拟即。public virtual Name {get; set; }在 Item 类中使用访问器?由于 Helment 和 Armor 从 Item 类下降。它将强制它们必须被覆盖......

希望这会有所帮助,最好的问候,汤姆。

于 2010-01-28T21:26:09.357 回答
0

所以这取决于你想做什么......

使类抽象强制所有子类实现该类(及其抽象函数等),但是如果您希望一个函数具有基本功能并且可以覆盖该函数,那么我建议不要创建该类抽象并使特定函数变为虚拟,因此当虚拟函数未被覆盖时,将调用基函数。

并且总是可以选择创建具有相同名称的“新”属性,但我认为这不是一个好习惯。

希望有帮助。

于 2010-01-28T21:40:07.007 回答
0

我认为您仍然可以在抽象类中使属性虚拟化,因此应该可以解决您的问题。

您可以将值设置为基本抽象类中的特定内容,这里是一个示例:

public abstract class Item
{
   public virtual string Name 
   { 
         get {return m_strName;} 
         set {m_strName = value;}
   }

public abstract class Armor : Item
{
   public override string Name { get; set; } // if you want to override it 
}

public class Helmet : Armor
{
   public override string Name { get; set; } // if you want to override it
}
于 2010-01-28T23:00:19.023 回答