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

发布于 2024-08-19 16:40:52 字数 597 浏览 12 评论 0原文

我有一个角色扮演游戏的类结构,如下所示...

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 中删除“abstract”,然后删除 Armor 和 Helmet 中覆盖的“Name”属性。如果我这样做,代码看起来会更干净一些,但我可能会忘记在这些派生类中设置 base.Name。

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

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

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

I have a class structure for a role playing game which looks like this...

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

Basically, I am trying to force every derived type to include a "Name" property. Is this the best way to do it? I know I can remove "abstract" from Item.Name and then remove the overriden "Name" properties in Armor and Helmet. If I do that the code looks a little cleaner but I might forget to set the base.Name in these derived classes.

Could someone help show me the best way to do this?

EDIT:
Sorry, let me clarify my question a little more. I want to make sure of 2 things.
1) Name property exists in all derived classes
2) Name property is not null or empty

I basically want to force any class that derives from Item (and is not abstract) to have a value for Name.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

街角卖回忆 2024-08-26 16:40:52

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

但我可能忘记设置
这些派生类中的 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)
    {

    }
}

然后您还可以使该属性成为:

  • 抽象以确保它存在于每个派生类中,都有自己的
  • 虚拟实现,以提供基本实现以及所有要覆盖的实现。

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

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

It sounds like you are worried about initialising properties?

but I might forget to set the
base.Name in these derived classes.

One way the you can force the Name property to be set is to include this setter in your base class constructor like so:

public class MyBaseClass
{
    private string _name;

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

Then everything that derives from MyBaseClass must satisfy that constructor:

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

    }
}

Then you can also make the property either:

  • abstract to ensure that it exists in each derived class with its own implementation
  • virtual to provide a base implementation and all it to be overridden.

I'm not going to venture whether the above is good design, but it would work to ensure that all derived classes have a valid name property when instantiated.

Another approach, as other answers suggest, is to implement a virtual property that throws an exception in its base implementation.

追星践月 2024-08-26 16:40:52

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

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

public abstract class Armor : Item
{ }

public class Helmet : Armor
{ }

You only need to define Name in the base class, and do not need to specify it as abstract. It will still be available as a property in all derived classes.

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

public abstract class Armor : Item
{ }

public class Helmet : Armor
{ }
狼性发作 2024-08-26 16:40:52

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

那么该对象的名称最终就会变得很愚蠢。

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

If I do that the code looks a little cleaner but I might forget to set the base.Name in these derived classes.

Then the name of the object will just end up being something silly.

Better yet, have name start out as null. Then you'll get an exception if you forget to initialize the name but someone tries to use it, and you'll know you have to fix it.

作业与我同在 2024-08-26 16:40:52

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

如果您只想强制执行以下事实:在创建 Item 时,明确设置了名称,您可以通过隐藏零参数构造函数并公开接受该名称的构造函数来强制执行此操作。

看一下这段代码:

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

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

Mike is right that if you just want to use the property "Name" on all derived objects, you don't need it to be marked abstract at all as it's inherited.

If you want to just force the fact that when Items are created, a name is definitely set, you could force it through hiding the zero-parameter constructor and exposing a constructor that accepts the name.

Take a look at this code:

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() {}
}

The above definitions mean that:

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

This forces that any instance of the classes must define the name at time of creation. One possible solution anyway...

稚气少女 2024-08-26 16:40:52

将使 Name 成为虚拟的 ie。 公共虚拟名称 {get;放; } 访问器可以在 Item 类中使用吗?由于头盔和盔甲源自物品类。它将强制要求它们必须被覆盖...

希望这会有所帮助,
此致,
汤姆.

Would making Name a virtual ie. public virtual Name {get; set; } accessor be used in the Item class? Since Helment and Armor descend from the Item class. It would enforce that they must be overridden...

Hope this helps,
Best regards,
Tom.

吾性傲以野 2024-08-26 16:40:52

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

使类抽象强制所有子类实现该类(及其抽象函数等),但是如果你希望一个函数具有可以重写的基本功能那么我建议不要将类设为抽象,而是将特定函数设为虚拟,这样当虚拟函数不被覆盖时,就会调用基函数。

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

希望有帮助。

so it depends what you want to do ...

making class abstract forces all the sub-classes to implement the class (and its abstract functions, etc.), but if you want a function to have a base functionality with the possibility to override the function then i'll suggest not making the class abstract and making the specific function virtual instead, thus when the virtual function is not being overwritten, and base function will be called.

and there's always options to create a "new" properties with the same name, but i don't think that's a good practice.

hope that helps.

心凉 2024-08-26 16:40:52

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

您可以将该值设置为基抽象类中的特定值,
这是一个例子:

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
}

i think you can still make the property virtual within a abstract class, thus that should solve your problem.

You can set the value to something specific in the base abstract class,
here an example :

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文