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

发布于 2024-12-18 05:22:50 字数 2055 浏览 2 评论 0原文

我一直在尝试将正确的 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 方法设置“Action”属性不正确。在所有情况下,aa DocumentActionReplaceByTag 都需要 FindText,因此我将其放入构造函数中:

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

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

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

I have been making some hamfisted attempts to apply correct OOP principles to my project. I have an abstract class called DocumentSection, and several classes deriving from it (DocumentSectionView, DocumentSectionText, etc). Similarly I have an abstract class (DocAction) with several classes deriving from it (DocumentActionReplaceByTag, DocumentSectionAppend, etc). Each DocumentSection has a DocumentAction within it.

My understanding of all this inheritance business is that by specifying a 'DocumentAction', this would allow any of those derived classes to be put in its place, and that any properties/methods from the base class would be available, as well as any specified in the concrete class I instantiate. So in the below example, I expected to be able to see the PerformAction method (leaving the virtual/override keywords out of the mix for now). And it is available.

However, because I went v.DocAction = new DocumentActionReplaceByTag();, I would also have expected my ReplaceActionFindText property to be visible.

Obviously I've got it wrong somewhere - any comments appreciated.

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:
I've marked an answer as correct, but thought I'd add the fruits of my further thought on this matter for those coming across this later:

a) As pointed out, my intentions were broadly right but my method wrong. Setting the 'Action's property from the Main method was not correct. In all cases, a a DocumentActionReplaceByTag requires the FindText so I placed it in the constructor:

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

From then on, a constructor with 0 arguments will rightly fail, and prevent a case where the action is executed but no findtext is specified.

b) Polymorphism works fine now, because my extra property findtext has been populated, and running PerformAction will run correctly regardless of the action type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你怎么敢 2024-12-25 05:22:50

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

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

编辑:

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

如果您必须转换为派生类型,那么您就违反了里氏替换原则,这意味着任何派生类型type 应该可以用来代替基本类型 - 如果您需要特定的强制转换,则显然不是这种情况。

重新考虑您的设计 - 您是否真的需要具有基类类型的属性,如果需要,当前仅在一种特定派生类型中的方法是否最好也在基类型中?

Because you are assigning your derived class to a property with the type of the base class only the methods and properties of the base class will be available. And this makes sense since you could have assigned any instance of a class that derives from the base class - so any derived methods cannot be used in this context.

This is one of the OOP principles - your derived class instances may be used as an instance of a base class (but not the other way round)

Edit:

To elaborate on the solution proposed by @sll to cast to a particular derived class type: Don't do it! It is a workaround but not in the interest of the overall design.

If you have to cast to a derived type then you are violating the Liskov substitution principle meaning that any derived type should be usable in place of the base type - that's clearly not the case if you need a specific cast.

Rethink your design - do you really need a property with the base class type and if so are the methods currently only in one particular derived type better off being in the base type as well?

感情洁癖 2024-12-25 05:22:50

v 引用类型属于 DocumentSectionView,它不知道 DocumentActionReplaceByTag 类的方法,即使底层实例是 DocumentActionReplaceByTag code> 正如您所分配的那样。您需要对其进行强制转换才能访问派生类成员:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText

此外,在某些情况下,当无法强制转换底层实例时,这非常好,因此应跳过代码的某些部分,然后您可以使用 作为操作员

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

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

The v reference type is of the DocumentSectionView which is not aware of methods of the DocumentActionReplaceByTag class even underlying instance is of DocumentActionReplaceByTag as you've assigned it. You need to cast it to be able accesing derived class members:

((DocumentActionReplaceByTag)v.DocAction).ReplaceActionFindText

Also in some cases this is pretty fine when underlying instance could not be casted so some part of code should be skipped, then you can use exception-safe way of casting using as operator:

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

My suggestions are only to help you understand C# side of question, regarding overall design and approach please see BrokenGlass's answer.

绝影如岚 2024-12-25 05:22:50

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

No, in your example, since DocAction is only a DocumentAction, you will only be able to see the properties of a DocumentAction, no matter which derived type of DocumentAction is used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文