我一直在努力尝试将正确的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都将正确运行。
答案 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
的属性使用。