Видимость свойств в производных классах (C #) - PullRequest
2 голосов
/ 27 ноября 2011

Я предпринял несколько попыток применить правильные принципы ООП к моему проекту. У меня есть абстрактный класс с именем DocumentSection и несколько классов, производных от него (DocumentSectionView, DocumentSectionText и т. Д.). Точно так же у меня есть абстрактный класс (DocAction) с несколькими производными классами из него (DocumentActionReplaceByTag, DocumentSectionAppend и т. Д.). В каждом DocumentSection есть DocumentAction.

Мое понимание всего этого бизнеса наследования заключается в том, что, указав 'DocumentAction', это позволило бы поставить на место любой из этих производных классов, и что любые свойства / методы из базового класса также будут доступны. как указано в конкретном классе я экземпляр. Таким образом, в приведенном ниже примере я ожидал, что смогу увидеть метод PerformAction (оставив ключевые слова virtual / override вне смеси пока). И это доступно.

Однако, поскольку я пошел v.DocAction = new DocumentActionReplaceByTag ();, я также ожидал, что мое свойство ReplaceActionFindText будет видимым.

Очевидно, что где-то я ошибся - любые комментарии приветствуются.

class Program
{
    static void Main(string[] args)
    {
        DocumentSectionView v = new DocumentSectionView();
        v.DocAction = new DocumentActionReplaceByTag();

        // would like to go:
        //v.DocAction.ReplaceActionFindText...

        Console.ReadLine();
    }   
}    
public abstract class DocumentSection
{
    public abstract string GetContent();
    public DocumentAction DocAction { get; set; }
}
public class DocumentSectionView : DocumentSection
{
    public string ViewPath { get; set; }
    public dynamic ViewModel { get; set; }

    public override string GetContent()
    {
        return "test";
    }
}    
public abstract class DocumentAction
{
    void PerformAction(StringBuilder sb, string content);
}
public class DocumentActionReplaceByTag : DocumentAction
{
    public string ReplaceActionFindText { get; set; }
    public void PerformAction(StringBuilder sb, string content)
    {
        sb.Replace(ReplaceActionFindText, content);
    }
}

EDIT: Я пометил ответ как правильный, но решил добавить плоды моей дальнейшей мысли по этому вопросу для тех, кто сталкивался с этим позже:

а) Как указывалось, мои намерения были в целом правильными, но мой метод ошибочным. Установка свойства 'Action из метода Main была неверной. Во всех случаях a DocumentActionReplaceByTag требует FindText, поэтому я поместил его в конструктор:

    public DocumentActionReplaceByTag(string replaceActionFindText)
    {
        this.ReplaceActionFindText = replaceActionFindText;
    }

С этого момента конструктор с 0 аргументами будет по ошибке работать и предотвращать случай, когда действие будет выполнено, но не найден findtext.

b) Полиморфизм теперь работает нормально, потому что мое дополнительное свойство findtext заполнено, и запуск PerformAction будет выполняться правильно независимо от типа действия.

Ответы [ 3 ]

2 голосов
/ 27 ноября 2011

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

Это один из принципов ООП - экземпляры вашего производного класса могут использоваться как экземпляр базового класса (но не наоборот)

Edit:

Чтобы развить решение, предложенное @sll для приведения к конкретному производному типу класса: не делайте этого! Это обходной путь, но не в интересах общего дизайна.

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

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

2 голосов
/ 27 ноября 2011

Тип ссылки v относится к DocumentSectionView, который не знает о методах класса DocumentActionReplaceByTag, даже если базовый экземпляр имеет DocumentActionReplaceByTag, как вы его назначили.Вам нужно привести его, чтобы иметь возможность доступа к производным членам класса:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText

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

var typedAction = v.DocAction as DocumentActionReplaceByTag;
if (typedAction != null)
{
   // accessing the typedAction.ReplaceActionFindText property
}

Мои предложения предназначены только для того, чтобы помочь вам понять сторону вопроса C #, относительно общего дизайна и подхода, см. ответ BrokenGlass.

0 голосов
/ 27 ноября 2011

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

...