views:

204

answers:

7

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.

+4  A: 

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
{ }
Mike
+1  A: 

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.

Anon.
A: 

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.

tommieb75
the virtual keyword only specifies that the member 'can' be modified (I.e. overriden) by derived types, not that it must.
KP
@KevinP: maybe you're right but the OP says 'but I might forget to set the base.Name in these derived classes', what do you think?
tommieb75
i edited my question to make it more clear. i want to make sure Name always has a value in all derived classes. but maybe that's not something i can enforce from the base class level?
mikedev
+1  A: 

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...

KP
+5  A: 

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.

David Hall
I just typed the same thing (pretty much exactly!) but you win by 40 seconds :D
Mark Simpson
@David are you saying that forcing all derived classes to have a valid name property might be bad design? or that this way of doing might be bad design? if the former, could you please shed some light on why?I just figured that enforcing some rules for derived classes would be a good thing.
mikedev
@mikedev - I've never implemented this type of pattern before, so I'm not sure if it is bad design or not. It usually takes me days if not weeks of looking at a new pattern before I make up my own mind on its merits (and them who is to say I'm right). I don't think there is anything wrong here though, if you take the is-a view of inheritance, Armour is-a Item, and all items must have a name, which this achieves. It meets the requirement and doesn't have any obvious downside beyone forcing all future items to have names.
David Hall
A: 

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.

aggietech
one reason i need the class to be abstract is because i never want to create an instance of Item or Armor. Only the derived type of "Helmet" is a valid object in this example
mikedev
A: 

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