C # Наследование, чтобы скрыть унаследованные Члены - PullRequest
2 голосов
/ 19 января 2012

Я читал другие темы, такие как this , но у меня они не работали.

У меня есть два класса:

public class ClassA 
{
    public string _shouldBeInteger;
    public string _shouldBeBool;
    public string _shouldBeDateTime;
}

public class ClassB : ClassA
{
   public int? shouldBeInteger
    {
        get { return (_shouldBeInteger != null) ? Convert.ToInt32(Convert.ToDouble(_shouldBeInteger)) : new int?(); }
        set { _shouldBeInteger = Convert.ToString(value); }
    } 

  //... same thing with datetime etc.


}

Если я сейчас создаю новый объект ClassB, я получаю

 _shouldBeInteger, _shouldBeBool, _shouldBeDateTime;
 shouldBeInteger,shouldBeBool,shouldBeDateTime

Но я хочу скрыть _variables для пользователя. Установка их в ClassB будет переопределять их, но мне нужно получить к ним доступ, чтобы проанализировать строковые значения.

Обновление

Существует ClassC, заполняющий значения ClassAs, что главным образом является причиной, по которой они должны быть доступны для записи. Я не могу изменить способ работы, но я полностью контролирую ClassA и ClassB

ClassC //not changeAble for me
{
 //infomagic filling values of ClassA    
}

Установка переменных ClassA в private не будет работать, потому что программист ClassA произвел это странным образом.

Решение

Поскольку ClassA должен быть доступен для записи, но не для чтения другими классами, кроме наследуемых, я наконец-то получил это:

ClassA 
{ 
  public string _shouldBeInteger { protected get; set; } 
  //and so on
} 

, который заставляет ClassB работать с этими свойствами, не передавая их наружу. Intellisense по-прежнему показывает их, но вы можете использовать:

 [EditorBrowsable(EditorBrowsableState.Never)]

чтобы решить это.

Спасибо всем.

Ответы [ 5 ]

9 голосов
/ 19 января 2012

Я думаю, что вы можете решить вашу проблему, используя:

public class ClassA 
{
    protected string _shouldBeInteger;
    protected string _shouldBeBool;
    protected string _shouldBeDateTime;
}

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

ИЗМЕНЕНО после обновления пользователя:
Я не знаю, может ли это быть решением для вас, но попробуйте:

public class ClassB : ClassA
{
    public new int? _shouldBeInteger
    {
        get { return (base._shouldBeInteger != null) ?
                     Convert.ToInt32(Convert.ToDouble(base._shouldBeInteger)) : 
                     new int?(); }
        set { base._shouldBeInteger = Convert.ToString(value); }
    }
}
4 голосов
/ 19 января 2012

Наследование не может скрывать участников, как вы думаете. Модификатор new существует для того, чтобы «скрывать» базовый элемент, но это не очень удобно при разговоре с базовыми типами.

http://msdn.microsoft.com/en-us/library/435f1dw2.aspx

Вы можете либо изменить уровень доступа к полям (предпочтительный способ), либо вы можете обернуть класс вместо наследования от него и предоставить простые сквозные методы для делегирования обернутому классу. Это называется Pattern Adapter :

public class ClassB
{
    private ClassA _wrappedClass;
}

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

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

1 голос
/ 19 января 2012

Проблема в том, что вы объявили поля общедоступными в базовом классе. Чтобы не нарушать полиморфную природу наследования, все общедоступное в базовом классе также должно быть общедоступным во всех производных классах. Если бы вы могли изменить это, вы бы никогда не были уверены, что ClassB может быть передан чему-то, ожидающему ClassA.

Следовательно, как и предполагали другие, вы, вероятно, хотите, чтобы поля базового класса были объявлены защищенными, что похоже на закрытое, за исключением того, что их могут видеть производные классы.

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

Если это тоже не подходит, то, вероятно, стоит подумать об использовании композиции вместо наследования, потому что принцип замещения фактически мешает вам, и это фундаментальное наследование.

0 голосов
/ 19 января 2012
public class ClassB
{
    private int shouldBeInteger;

    public int ShouldBeInteger
    {
        get { return shouldBeInteger; }
        set { shouldBeInteger = value; }
    }

}

ИЛИ

  public class ClassB
  {

    public int ShouldBeInteger{ get; set; }

  }

В обоих случаях ShouldBeInteger будет доступен вне класса.

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

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

, что и выше.Это автоматически реализованное свойство.

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

0 голосов
/ 19 января 2012

Если у вас нет контроля над ClassA, вам нужно создать класс оболочки / адаптера следующим образом:

public class ClassB
{
    private readonly _classA = new ClassA();

    public int? shouldBeInteger
    {
        get
        {
            return (this._classA._shouldBeInteger != null)
                ? Convert.ToInt32(Convert.ToDouble(this._classA._shouldBeInteger))
                : new int?();
       }
        set
        {
            this._classA._shouldBeInteger = Convert.ToString(value);
        }
    } 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...