你啥时候使用“受保护的内部”访问修饰符?

Posted

技术标签:

【中文标题】你啥时候使用“受保护的内部”访问修饰符?【英文标题】:When would you use the "protected internal" access modifier?你什么时候使用“受保护的内部”访问修饰符? 【发布时间】:2010-09-17 08:05:49 【问题描述】:

您可能已经知道,.NET Framework 的 protected internal 访问修饰符以一种奇怪的方式工作:这并不意味着该类受到保护 AND internal,表示该类是protected OR internal;也就是说,修改后的类或成员可以从同一程序集以及从同一层次结构中访问。

所以,知道这一点:您什么时候使用它?能给我举个例子吗? .NET 基类库中是否有一个很好的启发性用法示例?

【问题讨论】:

我不知道。我一直以为是 AND。 这是您第一次阅读时的想象。我想任何人都可能以同样的方式猜测。 是的,我想它第一次就吸引了所有人。 AND/OR 逻辑有点混乱。在 C# 中,成员默认是私有的,您可以根据需要打开访问权限。 Public 提供所有访问权限,protected 提供对派生类的访问权限,internal 提供对同一程序集中所有类的访问权限。通过这种推理,受保护的内部是受保护的和内部的(您可以访问派生类和同一程序集中的类)。大多数人的想法是相反的(增加限制而不是取消限制)。 The mandatory link to Eric Lippert's post on this topic. 【参考方案1】:

我很少需要使用这种访​​问修饰符组合,因为我认为除了最极端的情况外,这表明设计不佳。但是,有时需要让类型转换器和编辑器等辅助类访问程序集中的方法,但只允许派生类在其他用例中访问它。

一个示例可能是将类型转换为类型转换器的字符串的调用。 ToString() 通常不用于此目的,因此您可能有一个您希望类型转换器使用的 ToPersistableString() 调用,因此您将其设为 internal。然后,您决定从您的类派生的人很可能希望将此调用用作他们自己的派生类持久性方案的一部分,因此您也将其设为 protected

.NET Framework 使用Control 上的AccessibilityNotifyClientsprotected internal。使用Reflector,我可以看到这样做是为了让CheckListBoxCheckedItemCollection 可以在更改检查状态时访问它。

【讨论】:

这个答案很难理解;我真的不明白你的类型转换器在做什么或为什么这样做。首先,它只适用于定义了ToPersistableString() 的类型(即几乎没有)。其次,为什么要将类型名称转换为字符串而不是使用typeof,或者通过.GetType().ToString()获取名称?为什么叫它PersistableString 而不是TypeNameString - 它有什么持久性?如果你能澄清这一点并提供你的示例类型转换器的代码示例,我会支持这个答案。 @Jez:这是一个例子。它只是说明您可能在内部有两种类型(您的类型及其转换器)需要访问该方法,但您可能还希望能够覆盖该方法以在派生类中扩展它。类型转换器允许您在不同类型之间进行转换:ToPersistableString 将提供该类型的字符串版本,以允许将该类型持久化为字符串。没有人在这里转换类型名称。有关类型转换器的更多信息,请参阅 MSDN (msdn.microsoft.com/en-us/library/…)【参考方案2】:

我已将它用于您希望能够在单独的名称空间中用于单元测试的内部方法,单元测试名称空间包含该类的子类。这允许访问受保护的方法。

也就是说,有一个论点是公开所有内容以进行单元测试。

【讨论】:

你的意思是命名空间还是程序集?您可能需要考虑 InternalsVisibleToAttribute 来克服测试问题 [assembly: InternalsVisibleTo("Your.Tests")] 我的意思是命名空间,如果我必须用内部的东西对一个类进行单元测试,我会创建一个新项目,但要使命名空间相同,以便我可以访问它们。我知道这可能不是最佳实践,但它可以工作,并且单元测试没有编译到我的部署中。尽管它看起来很有趣,但我会研究该属性。【参考方案3】:

我想添加一个来自 ASP.Net MVC 框架的示例:

public abstract class Controller : ControllerBase, <Omitted Interfaces>

     protected internal ViewResult View() 
            return View(null /* viewName */, null /* masterName */, null /* model */);
        

     protected internal ContentResult Content(string content) 
            return Content(content, null /* contentType */);
        


【讨论】:

以上是关于你啥时候使用“受保护的内部”访问修饰符?的主要内容,如果未能解决你的问题,请参考以下文章

受保护的内部[重复]

受保护的内部成员 [重复]

访问修饰符

java访问控制修饰符之default

访问修饰符与可选修饰符static的使用

使用受保护的访问修饰符覆盖没有访问修饰符的方法