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

本文关键字:可见性 属性 派生 | 更新日期: 2023-09-27 18:15:55

我一直在尝试将正确的OOP原则应用到我的项目中。我有一个抽象类称为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);
    }
}

编辑:我已经把一个答案标记为正确,但我想我应该把我对这个问题的进一步思考的成果添加到以后遇到这个问题的人身上:

a)正如所指出的,我的意图大体上是正确的,但我的方法是错误的。从Main方法设置动作的属性不正确。在所有情况下,一个DocumentActionReplaceByTag需要FindText,所以我把它放在构造函数中:

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

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

b)多态工作得很好,因为我的额外属性findtext已经填充,运行PerformAction将正确运行,无论操作类型。

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

因为您将派生类分配给具有基类类型的属性,因此只有基类的方法和属性可用。这是有意义的,因为您可以将派生自基类的类的任何实例赋值给,因此任何派生方法都不能在此上下文中使用。

这是OOP原则之一——你的派生类实例可以用作基类的实例(但不能反过来)

编辑:

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

如果必须强制转换为派生类型,则违反了Liskov替换原则,即任何派生类型都应该可用来代替基类型——如果需要特定强制转换,显然不是这样的。

重新考虑你的设计——你真的需要一个带有基类类型的属性吗?如果是的话,当前只在一个特定派生类型中的方法是否也最好在基类型中呢?

v引用类型是DocumentSectionView的,它不知道DocumentActionReplaceByTag类的方法,即使底层实例是您指定的DocumentActionReplaceByTag。您需要强制转换它以能够访问派生类成员:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText

在某些情况下,当底层实例无法强制转换,因此应该跳过部分代码时,这是非常好的,然后您可以使用异常安全的强制转换方式使用as操作符:

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

我的建议只是帮助你理解c#方面的问题,关于整体设计和方法请参阅BrokenGlass的回答

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