如何强制派生类包含具有默认值的某些属性

时间:2010-01-28 21:19:36

标签: c# abstract-class derived-class

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

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; }
}

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

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

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

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

7 个答案:

答案 0 :(得分:9)

听起来你担心初始化属性?

  

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

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

public class MyBaseClass
{
    private string _name;

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

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

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

    }
}

然后您也可以创建该属性:

  • abstract以确保它在每个派生类中都有自己的实现
  • 虚拟以提供基本实现,并将其全部覆盖。

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

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

答案 1 :(得分:4)

您只需要在基类中定义Name,而不需要将其指定为抽象。它仍将作为所有派生类中的属性提供。

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

public abstract class Armor : Item
{ }

public class Helmet : Armor
{ }

答案 2 :(得分:2)

  

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

然后,对象的名称最终将成为愚蠢的东西。

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

答案 3 :(得分:2)

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

如果您只想强制创建Items时,确实设置了一个名称,您可以强制它隐藏零参数构造函数并公开接受该名称的构造函数。

看看这段代码:

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

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

答案 4 :(得分:0)

将Name命名为虚拟ie。 Item类中使用public virtual Name {get; set; }访问器?因为Helment和Armor来自Item类。它会强制它们必须被覆盖......

希望这有帮助, 最好的祝福, 汤姆。

答案 5 :(得分:0)

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

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

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

希望有所帮助。

答案 6 :(得分: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
}