限制子实现的方法范围

时间:2017-10-11 21:25:15

标签: c# .net

我希望这不是重复但我无法通过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而不诉诸abstractprotected virtual的方式?创建这样的方法的示例是Object.Finalize(),如here所示。

或者,为了在某种程度上反转这个问题,为什么你要创建一个方法protected virtual,除非确保任何实现的范围有限?或者还有另一种方法可以做同样的事情吗?

3 个答案:

答案 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或其他来源代码规则引擎集成到您的持续构建过程中。开发人员仍然可以添加该方法,但是如果他们这样做,您可以设置一个规则使其失败。