我希望这不是重复但我无法通过Google或SO搜索找到。如果我想强制方法的覆盖方法实现的可访问性为protected
,那么我唯一的选择是创建为abstract
还是protected virtual
?我知道接口指定了声明,但是将可访问性/范围留给了类实现,但我想确定。
我想知道/确定限制方法范围的唯一方法是通过abstract
\ protected virtual
来提供&#34的语义;这适用到类实现或子覆盖实现"。
一个代码示例来说明。我知道我可以执行以下操作并限制实现的范围,如此;
public class BaseClass
{
protected virtual void OnlyMeOrChildrenCanDoAction()
{
// leave empty as current class is structural/conceptual
// but child instances may need it
}
}
通过以上操作,我保证子实现只能override
OnlyMeorChildrenCanDoAction()
为protected
而不是public
。
但有没有另一种限制protected
而不诉诸abstract
或protected virtual
的方式?创建这样的方法的示例是Object.Finalize()
,如here所示。
或者,为了在某种程度上反转这个问题,为什么你要创建一个方法protected virtual
,除非确保任何实现的范围有限?或者还有另一种方法可以做同样的事情吗?
答案 0 :(得分:3)
我认为你误解了virtual
的含义和用法。如果声明为virtual,则只能 覆盖父类中的方法。子类中的override方法必须与父类中的方法具有相同的可见性。
接口中声明的方法的实现总是public
。
声明方法abstract
与声明它virtual
具有相同的效果,除非你没有在你的类中实现它,并且从你的类派生的任何具体类必须实现它。
答案 1 :(得分:2)
从技术上讲,编译器不允许您在从父项覆盖方法时更改方法的访问修饰符,因此问题的答案是通过在类中声明一个受保护的方法,您只能使它可用派生类(无论是抽象类还是非抽象类都是一个单独的问题,并且对访问级别没有影响)。
但是,请记住,派生类可以以其他方式自由地公开函数,例如从公共方法调用受保护的方法,并且无法阻止它。
就“为什么”而言,你会有一个受保护的抽象成员,在模板方法模式的许多实现中都可以看到一个很好的例子。您可能有一个描述算法结构的抽象基类,并将每个步骤边界内发生的具体步骤留给派生类。在这种情况下,实现的一种方法是将基类声明为抽象,将公共方法用作算法的“入口点”,并将算法中使用的特定方法定义为受保护的抽象方法,以布置派生类的责任将是。这种模式很好地将公开只留给那些意图被世界消费的东西,但是可以从单元测试的角度提出一些挑战,有时通过提高辅助方法从受保护的方式到内部的可见性来解决。< / p>
答案 2 :(得分:1)
您不能使用c#语言来阻止派生类实现OnlyMeOrChildrenCanDoAction
的公共版本。即使您将其标记为protected virtual
,派生类也可以使用new
关键字来覆盖该方法并更改其可访问性。例如:
public class BaseClass
{
protected virtual void OnlyMeOrChildrenCanDoAction()
{
// leave empty as current class is structural/conceptual
// but child instances may need it
}
}
public class DerivedClass : BaseClass
{
public new void OnlyMeOrChildrenCanDoAction()
{
Console.WriteLine("This is public.");
}
}
public class Program
{
public static void Main()
{
var b = new BaseClass();
//b.OnlyMeOrChildrenCanDoAction(); //Will not compile
var d = new DerivedClass();
d.OnlyMeOrChildrenCanDoAction(); //Look! It's public!
}
}
输出:
This is public.
DotNetFiddle上提供的代码。
如果您想保护来电者不要拨打OnlyMeOrChildrenCanDoAction
,最好的办法是让来电者只使用接口。如果接口中没有OnlyMeOrChildrenCanDoAction
,则调用者无法调用它,即使派生类决定将其作为公共类成员公开。无论如何,这是一个很好的SOLID设计。
另一方面,如果你不担心调用者,因为你担心自己的开发团队做坏事,也许你最好的选择是使用FxCop或其他来源代码规则引擎集成到您的持续构建过程中。开发人员仍然可以添加该方法,但是如果他们这样做,您可以设置一个规则使其失败。