Как заставить производный класс включать определенные свойства со значением по умолчанию - PullRequest
8 голосов
/ 29 января 2010

У меня есть структура классов для ролевой игры, которая выглядит следующим образом ...

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, а затем удалить переопределенные свойства «Имя» в броне и шлеме. Если я сделаю это, код выглядит немного чище, но я могу забыть установить base.Name в этих производных классах.

Может ли кто-нибудь помочь мне показать лучший способ сделать это?

EDIT: Извините, позвольте мне прояснить мой вопрос немного больше. Я хочу убедиться в 2 вещах. 1) Свойство Name существует во всех производных классах 2) Имя свойства не является нулевым или пустым

Я в основном хочу заставить любой класс, производный от Item (и не являющийся абстрактным), иметь значение для Name.

Ответы [ 7 ]

9 голосов
/ 29 января 2010

Похоже, вы беспокоитесь об инициализации свойств?

но я могу забыть установить 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)
    {

    }
}

Тогда вы также можете сделать свойство либо:

  • реферат, чтобы убедиться, что он существует в каждом производном классе с его собственной реализацией
  • виртуальный, чтобы обеспечить базовую реализацию и все это должно быть переопределено.

Я не собираюсь рисковать, если вышеприведенное является хорошим дизайном, но оно будет работать, чтобы гарантировать, что все производные классы имеют действительное свойство имени при создании экземпляра.

Другой подход, как предлагают другие ответы, заключается в реализации виртуального свойства, которое выдает исключение в своей базовой реализации.

4 голосов
/ 29 января 2010

Вам нужно только определить Name в базовом классе, и не нужно указывать его как абстрактный. Он все еще будет доступен как свойство во всех производных классах.

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

public abstract class Armor : Item
{ }

public class Helmet : Armor
{ }
2 голосов
/ 29 января 2010

Майк прав, что если вы просто хотите использовать свойство «Имя» для всех производных объектов, вам не нужно, чтобы оно вообще отмечалось как абстрактное, поскольку оно наследуется.

Если вы хотите просто форсировать тот факт, что при создании Предметов определенно задается имя, вы можете форсировать его, скрывая конструктор с нулевым параметром и выставляя конструктор, который принимает имя.

Посмотрите на этот код:

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

Это заставляет любой экземпляр классов определять имя во время создания. В любом случае одно из возможных решений ...

2 голосов
/ 29 января 2010

Если я сделаю это, код выглядит немного чище, но я мог бы забыть установить base.Name в этих производных классах.

Тогда имя объекта просто окажется глупым.

Еще лучше, name начинаются как null. Тогда вы получите исключение, если вы забудете инициализировать имя, но кто-то попытается его использовать, и вы будете знать, что вам нужно это исправить.

0 голосов
/ 29 января 2010

я думаю, что вы все еще можете сделать свойство виртуальным в абстрактном классе, что должно решить вашу проблему

Вы можете установить значение на что-то конкретное в базовом абстрактном классе, вот пример:

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
}
0 голосов
/ 29 января 2010

так что это зависит от того, что вы хотите сделать ...

создание абстрактного класса заставляет все подклассы реализовать класс (и его абстрактные функции и т. Д.), Но если вы хотите, чтобы функция имела базовую функциональность с возможностью переопределения функции, то я предлагаю сделав класс абстрактным и сделав конкретную функцию виртуальной, вместо этого, когда виртуальная функция не будет перезаписана, будет вызвана базовая функция.

и всегда есть варианты создания "новых" свойств с тем же именем, но я не думаю, что это хорошая практика.

надеюсь, это поможет.

0 голосов
/ 29 января 2010

сделает имя виртуальным, т.е. public virtual Name {get; set; } метод доступа будет использоваться в классе Item? Так как Helment и Armor спускаются из класса Item. Это привело бы к тому, что они должны быть переопределены ...

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

...