VB.Net中Protected成员暴露Public类型为何仅触发报错?
咱们先把你的代码和错误信息清晰列出来:
你的代码结构
Public Class MainClass Private Class HiddenClass End Class Private Class ChildA Inherits HiddenClass End Class Private Class ChildB Inherits HiddenClass End Class End Class Public Class BuildingBlock Protected lbl As Label Protected btn As Button Protected main As New MainClass() ' 设为Protected时报错 End Class
报错信息
'main' cannot expose type 'MainClass' outside the project through class 'BuildingBlock'
这本质上是VB.NET的访问级别一致性规则在约束你,核心逻辑是:成员的访问范围不能超过其数据类型的访问范围,或者说,你不能通过一个成员,把一个类型暴露给比该类型允许访问范围更广的代码。
现在逐个分析不同修饰符的情况:
1. 设为Private时无错误
Private成员只能被BuildingBlock类内部的代码访问,完全不会暴露给任何外部代码(包括项目内的其他类、外部项目的代码)。不管MainClass的访问级别是什么,只要BuildingBlock内部能访问它(这里MainClass是Public,当然可以),就不会出现“暴露类型到外部”的问题,所以编译器不会报错。
2. 设为Friend时无错误
Friend成员的访问范围是当前项目(程序集)内的所有代码。MainClass是Public,当前项目内的代码本来就可以自由访问它,所以成员的访问范围(仅项目内)比类型的访问范围(所有程序集)更严格,不会出现“把类型暴露到项目外”的情况,因此没问题。
3. 设为Public时无错误
Public成员的访问范围是所有程序集,和MainClass的Public访问级别完全一致——外部程序集既能访问main成员,也能访问MainClass类型,完全符合访问级别一致性规则,所以编译器不会报错。
4. 设为Protected或Protected Friend时报错
这两个修饰符的共同特点是:允许外部项目的子类访问该成员:
- Protected:允许当前类、当前项目的子类,以及外部项目的子类访问
main - Protected Friend:允许当前项目内的所有代码,以及外部项目的子类访问
main
而你的BuildingBlock是Public类,外部项目可以继承它并创建子类。此时,外部项目的子类能访问main成员,但这里存在一个矛盾:如果MainClass的访问级别不足以让外部项目的代码完整访问(比如隐含的访问限制,或是编译器判定存在跨程序集暴露的风险),就会触发编译器错误——子类能看到main成员,但无法正常访问它的类型MainClass,这违反了访问一致性规则。
你说改成Public后问题解决,是因为Public成员的访问范围和MainClass的Public范围完全匹配,外部程序集可以直接访问main和MainClass,不存在任何访问权限的矛盾。
总结一下:只有Protected和Protected Friend会允许外部项目的子类访问main,如果MainClass的访问级别无法覆盖这个跨程序集的访问范围,就会触发报错;而Private、Friend的访问范围被限制在当前项目内,Public则和MainClass的范围完全匹配,所以都没问题。
内容的提问来源于stack exchange,提问作者Skitzafreak

