2008-11-28 3 views
113

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

Я хочу определить его в базовом классе, поэтому я могу ссылаться на него в методе базового класса - например, переопределить ToString, чтобы сказать «Этот объект имеет тип property/field». У меня есть три способа, которые я могу видеть в этом, но мне было интересно: какой лучший или приемлемый способ сделать это? Новый вопрос, извините.

Вариант 1:
Использование абстрактной собственности и переопределить его на наследуемых классов. Это может быть принудительным (вы должны переопределить его), и это чисто. Но, кажется, немного неправильно возвращать значение жесткого кода, а не инкапсулировать поле, и это несколько строк кода, а не просто. Я также должен объявить тело для «набора», но это менее важно (и, вероятно, есть способ избежать того, чего я не знаю).

abstract class Father 
{ 
    abstract public int MyInt { get; set;} 
} 

class Son : Father 
{ 
    public override int MyInt 
    { 
     get { return 1; } 
     set { } 
    } 
} 

Вариант 2
я могу объявить публичное поле (или защищенное поле) и явно переопределить его в унаследованной классе. Пример ниже даст мне предупреждение использовать «новое», и я, вероятно, могу это сделать, но он чувствует себя не так, и он ломает полиморфизм, и это в целом. Не похоже, хорошая идея ...

abstract class Mother 
{ 
    public int MyInt = 0; 
} 

class Daughter : Mother 
{ 
    public int MyInt = 1; 
} 

Вариант 3
я могу использовать защищенное поле и установите его значение в конструкторе. Это кажется довольно аккуратным, но полагается на меня, гарантируя, что конструктор всегда устанавливает это и с несколькими перегруженными конструкторами всегда есть шанс, что какой-то путь кода не установит значение.

abstract class Aunt 
{ 
    protected int MyInt; 
} 

class Niece : Aunt 
{ 
    public Niece() 
    { 
     MyInt = 1; 
    } 
} 

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

ответ

107

Из трех решений только Вариант 1 является полиморфный ,

Поля сами по себе не могут быть переопределены. Именно поэтому Вариант 2 возвращает предупреждение ключевого слова.

Решение предупреждение не добавлять «новый» ключевое слово, но реализовать вариант 1.

Если вам нужно ваше поле, чтобы быть полиморфными вам нужно обернуть его в собственности.

Вариант 3 в порядке, если вам не требуется полиморфное поведение. Однако вы должны помнить, что когда во время выполнения происходит доступ к свойству MyInt, производный класс не имеет никакого контроля над возвращаемым значением. Базовый класс сам по себе способен вернуть это значение.

Вот как может выглядеть истинно полиморфная реализация вашего имущества, позволяя производным классам находиться в управлении.

abstract class Parent 
{ 
    abstract public int MyInt { get; } 
} 

class Father : Parent 
{ 
    public override int MyInt 
    { 
     get { /* Apply formula "X" and return a value */ } 
    } 
} 

class Mother : Parent 
{ 
    public override int MyInt 
    { 
     get { /* Apply formula "Y" and return a value */ } 
    } 
} 
0

Я бы выбрал вариант 3, но имеет абстрактный метод setMyInt, который подклассы принудительно реализуют. Таким образом, у вас не будет проблемы с производным классом, забывающим установить его в конструкторе.

abstract class Base 
{ 
protected int myInt; 
protected abstract void setMyInt(); 
} 

class Derived : Base 
{ 
override protected void setMyInt() 
{ 
    myInt = 3; 
} 
} 

Кстати, с вариантом один, если вы не указали set; в вашем абстрактном базовом классе, производному классу не придется его реализовывать.

abstract class Father 
{ 
    abstract public int MyInt { get; } 
} 

class Son : Father 
{ 
    public override int MyInt 
    { 
     get { return 1; } 
    } 
} 
0

Вы можете пойти с вариантом 3, если вы измените абстрактный базовый класс требовать значение свойства в конструкторе, вы не пропустите ни одного пути. Я бы действительно рассмотрел этот вариант.

abstract class Aunt 
{ 
    protected int MyInt; 
    protected Aunt(int myInt) 
    { 
     MyInt = myInt; 
    } 

} 

Конечно, вы тогда еще есть возможность сделать поле частным, а затем, в зависимости от необходимости, подвергая защищенный или общественный поглотитель собственности.

3

Вы могли бы определить что-то вроде этого:

abstract class Father 
{ 
    //Do you need it public? 
    protected readonly int MyInt; 
} 

class Son : Father 
{ 
    public Son() 
    { 
     MyInt = 1; 
    } 
} 

При установке значения, как неизменяемые, это гарантирует, что значение для этого класса остается неизменным в течение всего срока службы объекта.

Я полагаю, следующий вопрос: зачем он вам нужен?

+0

Static - это плохой выбор слов, поскольку он подразумевает, что значение распределяется между всеми экземплярами класса, что, конечно же, не является. – 2008-11-28 17:11:45

+0

Это правда. Я отредактирую его. – Ant 2009-01-09 14:43:31

15

Вариант 2 не является стартером - вы не можете переопределения поля, вы можете только скрыть их.

Лично я бы выбрал вариант 1 каждый раз. Я стараюсь постоянно держать поля в секрете. Это, конечно, если вам действительно нужно переопределить свойство. Другим вариантом является, чтобы иметь свойство только для чтения в базовом классе, который устанавливается из параметра конструктора:

abstract class Mother 
{ 
    private readonly myInt; 
    public int MyInt { get { return myInt; } } 

    protected Mother(int myInt) 
    { 
     this.myInt = myInt; 
    } 
} 

class Daughter : Mother 
{ 
    public Daughter() : base(1) 
    { 
    } 
} 

Это, вероятно, наиболее подходящим, если значение не изменяется в течение всего срока действия экземпляра.

+0

Можем ли мы сказать это сейчас не правильно на основе этого http://msdn.microsoft.com/en-us/library/9fkccyh4.aspx В статье msdn показано, что вы можете переопределить свойства – codingbiz 2014-09-02 23:17:28

+1

@codingbiz: где мой ответ говорит о свойствах? Поля и свойства - это не одно и то же. – 2014-09-03 05:23:21

6

вариант 2 - плохая идея. Это приведет к чему-то, что называется затенением; В основном у вас есть два разных члена «MyInt», один в матери, а другой в дочери. Проблема в том, что методы, которые реализуются в матери, будут ссылаться на «MyInt» матери, в то время как методы, реализованные в дочери, будут ссылаться на «MyInt» дочери. это может привести к серьезным проблемам с читабельностью и запутанности позже.

Лично я считаю, что лучший вариант - 3; поскольку она обеспечивает четкое централизованное значение, и можно ссылаться внутри детьми без хлопот определения их собственных полей - что проблема с опцией 1.

3

Вы можете сделать это

class x 
{ 
    private int _myInt; 
    internal virtual int myInt { get { return _myInt; } set { _myInt = value; } } 
} 

class y : x 
{ 
    private int _myYInt; 
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } } 
} 

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

0

Я сделал это ...

namespace Core.Text.Menus 
{ 
    public abstract class AbstractBaseClass 
    { 
     public string SELECT_MODEL; 
     public string BROWSE_RECORDS; 
     public string SETUP; 
    } 
} 

namespace Core.Text.Menus 
{ 
    public class English : AbstractBaseClass 
    { 
     public English() 
     { 
      base.SELECT_MODEL = "Select Model"; 
      base.BROWSE_RECORDS = "Browse Measurements"; 
      base.SETUP = "Setup Instrument"; 
     } 
    } 
} 

Таким образом, вы все еще можете использовать поле.

Смежные вопросы