为什么 C# 不支持受保护辅助功能和内部辅助功能的交集

本文关键字:功能 内部 不支持 为什么 受保护 | 更新日期: 2023-09-27 18:21:17

受保护的内部:

受保护的可访问

性和内部可访问性的结合(这比保护或单独的内部可访问性限制更少(

CLR 具有受保护的可访问性和内部可访问性的交集的概念,但 C# 不支持这一点。

所以我的问题是:

省略这个访问修饰符是什么意思,有具体的原因吗?那么为什么 C# 不应该支持它呢?

为什么 C# 不支持受保护辅助功能和内部辅助功能的交集

更新:C#7.2 使用访问修饰符 private protected 引入了它,这在某些方面似乎是错误的,但确实避免了我在下面描述的大部分混淆可能性,所以也许是最好的。

就个人而言,我已经想要过很多次了。有时,在程序集中公开一个类和从该类派生的一个或多个类public,有时基类的某些成员仅由这些派生类使用,而不应向其他程序集(通常是构造函数,以防止其他程序集具有派生自它的类(公开

。当然,尽可能

严格地定义您的访问权限总是好的,因此受保护和内部的交集正是这里想要的。

相反,我不得不通过声明成员internal来解决这个问题。现在,我的代码中可能存在错误,如果我使用一种允许我使用该交叉点的语言,这些错误就不会存在。

但是,请考虑缺点。

事实上,protected internal给予protectedinternal结合的方式存在一些混乱。这可能是最容易被误解的访问,由此类网站上的问题来判断。

我们应该怎么称呼它? internal protected ?你能想象人们多久会对protected internal感到困惑吗?我们想要一些更明确区分的东西,我们也希望internal protected也是如此(因为我们仍然增加了它混淆的可能性(。这不是一个不可能回答的问题,但减少关键字的数量也是一个好主意。

即使找到了命名问题的完美答案,引入另一个访问级别而导致混淆的可能性也不会完全消除。

因此,考虑到

这一点,让我们再次看看上行空间。我们不再需要通过使用 internal ,减少因不当使用此类成员而导致的错误。好的,这种情况多久出现一次,这些错误实际上有多大的可能性?真的不是经常,也不太可能。

因此,总的来说,虽然我发现自己偶尔希望 C# 有这个,但片刻的停顿通常会让我很高兴他们没有。

protectedinternal 的交集将降级为库外部代码的简单internal - 这意味着无论是从派生类还是其他方式,它都无法访问。

因此,protected internal intersection的唯一好处是约束自己,作为库的开发人员,除了来自库中的相同或派生类之外,不要访问类型/成员。它不会对库的使用者产生任何影响,因为它的语义与普通internal相同。

也就是说,我不会觉得在 C# 中允许它是不合理的。自律往往很有用;这就是为什么语言设计者区分privateinternal的原因,尽管两者对于外部消费者来说是相同的。

但是,由于交叉点和普通internal之间的区别很小,他们可能选择将其排除在外,以减轻开发人员将其与更有用的protected internal并集混淆的风险。

这是一个设计决策,但请考虑它的含义:

  • 只能由同一程序集中的派生类访问。

这不是一个非常有用的边界,我想不出一个明确的用例。
这就是为什么可能不值得想出一个新的关键字(-组合(。

我宁愿问为什么CLR支持它。我想是正交性。

那么为什么 C# 不应该支持它呢?

错误的问题。问题应该是"为什么 C# 应该支持 protected and internal

请记住,功能的自然状态是不实现它。实现一个功能在资源、测试以及机会成本(意味着它取代了其他功能(方面非常昂贵。因此,为了克服这笔费用,最好有一个非常明显的好处来实现克服这些成本的功能。

特别是,protected and internal的价值是什么?实际上没有充分的理由将可访问性限制为仅对同一程序集中的派生类。

IMO CLR 支持它很奇怪,但它确实如此。这并不意味着 C# 需要。

我想问同样的问题,但谢天谢地,SO 为我找到了这个问题。

我可以理解这样的观点,即它至少需要一个新的关键字,或者现有关键字的新语义,所以它没有得到支持,因为成本效益对它不利。

但是,我质疑由于用例狭窄或可能会使人们感到困惑而避免实现此 CLR 功能是否合法。

上面给出的一个论点是,它的唯一用途是强制执行自律。

但是,对于任何不public的可见性修饰符,也可以这样说。 同样,它仅适用于"单个库的单个开发人员"的想法显然也是错误的。 许多库都是由团队开发的,对于该团队中的开发人员来说,添加他或她希望仅限制为从其基础派生的内部类型的成员是完全自然的。

然后是这个场景:

internal class Foo {
}
public class PublicBase {
  protected Foo MyFoo { get; set; }
}

在这里的例子中,我有一个内部类型,我想在类上公开它,但我只想向派生类型公开它。 由于类型是内部类型,因此隐式表示同一程序集中的派生类型。 外部类型仍然可以合法地从此类型继承,但它们不需要使用此成员。

在这种情况下,我陷入了困境:我不能使用protected,也不能使用protected internal

相反,我必须使用 internal ,它错误地向团队的其他成员广播它应该从类外的代码中使用。 当然,我可以在上面贴一条评论(甚至可以在上面贴上Never EditorBrowsableAttribute,但这也会对内部继承者隐藏它(——但它不一样。

实际上,我可以实现此目的的唯一方法是在构建后使用 IL 重写来破解程序集 - 但我需要在编译时而不是在构建后使用这种可见性(或缺乏可见性(。

最终,关于">它将使用什么关键字"或">它将如何实现"的争论与我无关:我是程序员,而不是 C# 语言设计师。

同样,我不得不说像"好吧,protected internal对许多人来说已经足够令人困惑">这样的论点也是无关紧要的。 我接触过很多开发人员,无论是亲自还是虚拟的,他们不了解?:或通用约束之类的东西 - 你猜怎么着,他们不使用它们! 这并不意味着我不应该。

所以是的,我理解不实现它的原因 - 但我不同意他们 - 因此我对为什么 C# 不支持它的回答是因为 C# 设计者弄错了。

是的,我已经准备好迎接可能带给我家门口的热量:)

你总是可以做:

public MyExternallySealedClass
{
     internal MyExternallySealedClass() {...}
     ...
}

只要你不让任何外部使用者实例化对象,如果他们尝试派生它,你会关心什么?简短的回答,您请求的功能不会带来任何新内容,并且您已经拥有执行所请求的工具。

据我所知,您可以使用受保护和内部访问修饰符的交集,但不能使用您想要的解释(可能是因为 Henk 所说的话(:

  1. 受保护:类型或成员只能由同一类或结构中的代码或派生类中的代码访问。

  2. 内部:类型或成员可由同一程序集中的任何代码访问,但不能由另一个程序集访问。

  3. 受保护的内部:类型或成员可由同一程序集中的任何代码访问,也可以由另一个程序集中的任何派生类访问。