什么情况下会使用"protected internal"访问修饰符?

21
如您所知,.NET框架的protected internal访问修饰符的作用方式比较奇怪:它并不表示类是 protected internal,而是表示类是protected 或者 internal;也就是说,被修改的类或成员可以从 同一程序集内以及相同层级中访问。

因此,了解了这一点后,什么时候会使用它呢?您能给出一个例子吗?在.NET基类库中是否有一个好的、启示性的使用示例?


我不知道那个。我一直以为是AND。 - Bob King
这就是你第一次阅读时所想象的。我认为任何人都可能猜到同样的方式。 - Pablo Marambio
是的,我认为第一次都会被这个问题卡住。 - Jeff Yates
1
AND/OR逻辑有点令人困惑。在C#中,成员默认为私有,您可以根据需要打开访问权限。Public提供所有访问权限,protected提供派生类的访问权限,internal提供同一程序集中所有类的访问权限。按照这种推理,protected internal是受保护的并且是内部的(您同时授予派生类和同一程序集中的类访问权限)。大多数人认为它是相反的(添加限制而不是取消它们)。 - Lucas
3
这是需要翻译的内容: 必须链接到Eric Lippert关于此主题的帖子。 这个链接指向Eric Lippert在他的博客上发表的关于这个主题的文章,需要翻译。 - Roman Starkov
我认为Lucas的逻辑有些问题。protectedinternal各自描述了可以访问成员的实体集合。说internal语义上描述了不能访问成员的集合是不合理的!因此,protected internal指的是这两个集合的并集或非交集。无论您将默认访问级别视为什么,都没有关系。 - Matthew
3个回答

10

我很少使用这种访问修饰符的组合,因为在大多数情况下,除非是最极端的情况,否则它是设计不良的指标。但是,有时需要有辅助类(如类型转换器和编辑器)访问您程序集内的方法,但仅允许派生类在其他用例中访问。

一个例子可能是将类型转换为字符串以供类型转换器调用。通常不使用 ToString() 来进行该操作,所以您可以创建一个 ToPersistableString() 调用,并将其设置为 internal。然后,您决定从您的类派生的人很可能希望在其自己的派生类的持久性方案中使用此调用,因此您还将其设置为 protected

.NET Framework 使用
ControlAccessibilityNotifyClientsprotected internal 的。通过使用 Reflector,我可以看到这样做是为了在更改已选状态时使 CheckListBoxCheckedItemCollection 访问它。


这个答案很难理解,我不太明白你的类型转换器在做什么以及为什么要这样做。首先,它只能用于已定义了 ToPersistableString() 的类型(即几乎没有)。其次,为什么要将类型名称转换为字符串而不是使用 typeof 或通过 .GetType().ToString() 获取名称?而且为什么称之为 PersistableString 而不是 TypeNameString - 它有什么可持久化的东西吗?如果您能澄清一下并提供一个示例类型转换器的代码样本,我会点赞这个答案。 - Jez
1
@Jez:这只是一个例子。它仅仅说明你可能有两种类型(你的类型和它的转换器)需要访问该方法,但你也可能想要覆盖该方法以在派生类中扩展它。类型转换器允许你转换到不同的类型:ToPersistableString将提供类型的字符串版本,以允许类型持久化为字符串。这里没有任何人转换类型名称。有关类型转换器的更多信息,请参见 MSDN (http://msdn.microsoft.com/en-us/library/System.ComponentModel.TypeConverter.aspx) - Jeff Yates

2

我想在这里举一个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 */);
        }

}

2

我曾将它用于希望在单元测试的独立命名空间中使用的内部方法,该单元测试命名空间包含了该类的子类。这使得受保护的方法可以被访问。

话虽如此,有一种观点认为为了进行单元测试,应该将所有内容都设为公共。


你是指命名空间还是程序集?你可能需要考虑使用InternalsVisibleToAttribute来解决测试问题 [assembly: InternalsVisibleTo("Your.Tests")]。 - Mark Powell
我是说命名空间,如果我必须对一个包含内部内容的类进行单元测试,我会创建一个新项目,但保持命名空间相同以便访问它们。我知道这可能不是最佳实践,但它可以工作,并且单元测试不会编译到我的部署中。不过,我会研究一下那个属性,看起来很有趣。 - Omar Kooheji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接