派生类中属性的可见性(C#)

时间:2011-11-26 23:01:53

标签: c# inheritance properties abstract-class

我一直在努力尝试将正确的OOP原则应用到我的项目中。我有一个名为DocumentSection的抽象类,以及从中派生的几个类(DocumentSectionView,DocumentSectionText等)。类似地,我有一个抽象类(DocAction),它有几个派生自它的类(DocumentActionReplaceByTag,DocumentSectionAppend等)。每个DocumentSection都包含一个DocumentAction。

我对所有这些继承业务的理解是,通过指定'DocumentAction',这将允许任何这些派生类放在其位置,并且基类中的任何属性/方法都可用,以及我实例化的具体类中指定的任何一个。因此,在下面的示例中,我希望能够看到PerformAction方法(暂时将虚拟/覆盖关键字排除在混合之外)。它是可用的。

但是,因为我去了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);
    }
}

编辑: 我已经将答案标记为正确,但我认为我会为后来遇到的人添加我对此事的进一步思考的成果:

a)正如所指出的,我的意图大致正确但我的方法错了。从Main方法设置'Action的属性不正确。在所有情况下,DocumentActionReplaceByTag都需要FindText,所以我把它放在构造函数中:

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

从那时起,具有0个参数的构造函数将正确地失败,并防止执行操作但未指定findtext的情况。

b)多态性现在工作正常,因为我的额外属性findtext已被填充,并且无论操作类型如何,正在运行的PerformAction都将正确运行。

3 个答案:

答案 0 :(得分:2)

因为您要将派生类分配给具有基类类型的属性,所以只有基类的方法和属性可用。这是有道理的,因为您可以分配从基类派生的类的任何实例 - 因此任何派生的方法都不能在此上下文中使用。

这是OOP原则之一 - 您的派生类实例可以用作基类的实例(但不是相反)

修改

详细说明@sll提出的转换为特定派生类类型的解决方案:不要这样做!这是一种解决方法,但不符合整体设计的利益。

如果你必须强制转换为派生类型,那么你违反了Liskov substitution principle,这意味着任何派生类型都可以用来代替基类型 - 如果你需要一个特定的强制转换,情况显然不是这样。

重新考虑你的设计 - 你真的需要一个具有基类类型的属性吗?如果是这样的话,目前只有一种特定派生类型的方法最好也属于基类型?

答案 1 :(得分:2)

v引用类型属于DocumentSectionView,它不知道DocumentActionReplaceByTag类的方法,即使基础实例属于DocumentActionReplaceByTag,也是如此。您需要将其强制转换为能够访问派生类成员:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText

同样在某些情况下,当底层实例无法生成时会很好,因此应跳过某些部分代码,然后您可以使用as operator使用异常安全的转换方式:

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

我的建议只是为了帮助您理解C#方面的问题,关于整体设计和方法,请参阅BrokenGlass的答案。

答案 2 :(得分:0)

不,在您的示例中,由于DocAction只是DocumentAction,因此无论DocumentAction的派生类型是什么,您都只能看到DocumentAction的属性使用。