2017-10-11 67 views
0

我希望这不是重复的,但我无法通过Google或SO搜索找到。如果我想强制一个方法的重载方法的实现的可访问性为protected,是我的唯一选择,要么创建为abstractprotected virtual?我知道接口指定了声明,但将可访问性/范围留给了类实现,但我想确定。子方法的限制范围

我想知道/确定是否限制方法范围的唯一方法是通过abstract \ protected virtual给出“这适用于类实现或子覆盖实现”的语义。

要说明的代码示例。我知道我可以做到以下几点,并且像这样限制实现的范围;

public class BaseClass 
{ 
    protected virtual void OnlyMeOrChildrenCanDoAction() 
    { 
     // leave empty as current class is structural/conceptual 
     // but child instances may need it 
    } 
} 

通过做上述保证了我的孩子实现只overrideOnlyMeorChildrenCanDoAction()protected但不public可以。

但是,有没有另一种方法限制到protected而不诉诸于abstractprotected virtual?创建这种方法的示例是Object.Finalize(),如here所示。

或者,为了稍微反转问题,为什么要创建一个方法为protected virtual,除非确保任何实现的范围有限?或者还有另一种方法来做同样的事情吗?

+1

我很难理解你想问什么。我会建议添加一些代码示例。我不是downvoter,虽然 – maccettura

+0

我仍然很迷路。 – maccettura

+0

@maccettura如果我创建一个方法'保护虚拟'我保证只有子实现可以使用'protected'方法。我不能让子实现将它覆盖为“public”。上述方法是否仅限于此? – DiskJunky

回答

3

我认为你误解了virtual的含义和用法。如果声明为虚拟,您可以仅在重写父类中的方法。子类中的重写方法必须与父类中的方法具有相同的可见性。

在接口中声明的方法的实现始终为public

声明方法abstract与声明virtual具有相同的效果,除非您没有在类中实现它,并且从您的类派生的任何具体类必须实现它。

+0

接口实现的范围由实现者决定,除非实现者声明(只要我知道),否则不是“public”。这并没有回答我的问题:是否有另一种限制子实现范围的方法? – DiskJunky

+1

“要实现接口成员,实现类的相应成员必须是公共的,非静态的,并且与接口成员具有相同的名称和签名。” https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ –

+0

我站好了。这确实回答说,一个界面是不是要走的路 – DiskJunky

2

从技术上讲,编译器不允许在从父级重写它时更改方法的访问修饰符,所以问题的答案是通过将方法声明为受保护的类内部,可用于派生类(不论是否抽象是一个单独的问题,也不受访问级别的限制)。

但请记住,派生类可以自由地以某种其他方式公开该函数,例如从公共方法中调用受保护的方法,并且无法阻止该方法。至于“为什么”你有一个受保护的抽象成员,在Template Method模式的许多实现中可以看到一个很好的例子。您可能有一个抽象基类,它描述算法的结构,并将每个步骤边界内发生的具体步骤留给派生类。在这种情况下,实现的一种方法是将基类声明为抽象类型,使用公共方法作为算法的“入口点”,并将算法中使用的特定方法定义为受保护的抽象方法,派生类的职责将是。这种模式做了很好的工作,只公开那些有意被世界消费的东西,但是可以从单元测试的角度提出一些挑战,有时通过提高辅助方法从受保护到内部的可见性来解决这些问题。

+0

我的问题不是围绕'protected' /'public',而是围绕给孩子们一种实现功能的方式。也就是说,任何关于“公共”/“受保护”的混淆都可能更多地归结为我的问题的糟糕表述,对此,也表示道歉。你的观点是好的,说得好,只是不是我驾驶的。 – DiskJunky

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! 
    } 
} 

输出:对DotNetFiddle可用

This is public. 

代码。

如果你想保护呼叫者免受呼叫OnlyMeOrChildrenCanDoAction,你最好的选择是调用者只使用接口。如果OnlyMeOrChildrenCanDoAction不在接口中,即使派生类决定将其公开为公共类成员,调用者也无法调用它。无论如何,这是很好的SOLID设计。另一方面,如果你不太担心调用者,因为担心自己的开发团队做坏事,或许你最好的选择是使用FxCop或其他一些源代码规则引擎集成到您的持续构建过程。开发人员仍然可以添加该方法,但是如果他们这样做,您可以设置一个规则来使其失败。

+0

问题不在于限制访问(尽管你的答案是彻底的),它是围绕着,如果有另一种方式给孩子实现通过除'抽象','接口以外的机制实现功能的选项'或'保护虚拟'。根据迄今为止的答案,这是一个“不”。我很欣赏这个问题的原因是深奥的,但它主要围绕着为什么'Finalize'被实现。 – DiskJunky