【发布时间】:2011-08-27 22:32:05
【问题描述】:
为什么在 C# 中不允许派生类比其基类具有更大的可访问性。
例如,这将给出错误:不一致的可访问性:基类“BaseClass”比类“DerivedClass”更难访问
internal class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
以及为什么它在 Java 中被允许。
【问题讨论】:
为什么在 C# 中不允许派生类比其基类具有更大的可访问性。
例如,这将给出错误:不一致的可访问性:基类“BaseClass”比类“DerivedClass”更难访问
internal class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
以及为什么它在 Java 中被允许。
【问题讨论】:
更新:这个问题是the subject of my blog on November 13th 2012。谢谢你的好问题!
为什么在 C# 中不允许派生类比其基类具有更大的可访问性?
除了其他好的答案之外,请考虑这种情况。您和您的同事 Alice 正在处理同一个程序集的不同部分。 Alice 写了一个类:
public class ComplicatedClass
{
public void DoDangerousThing() { ... }
}
然后你写
public class EvenMoreComplicatedClass : ComplicatedClass
{
}
太好了。现在 Alice 得到 Bob 的安全审查,他们意识到 (1) 没有客户需要使用 ComplicatedClass,并且 (2) DoDangerousThing 暴露了一个安全漏洞,恶意代码可以利用。内部代码当然没有。
所以 Alice 将她的代码更改为
internal class ComplicatedClass
{
public void DoDangerousThing() { ... }
}
确定不需要在方法上将“public”更改为“internal”,因为 public 意味着“对可以看到此类的事物公开”,现在没有外部代码可以看到此类。
当 Alice 使用此更改重新编译时,您的代码会发生什么变化? 它应该无法编译。您假设用户需要查看基类,而 Alice 进行了违反该假设的更改。安全的做法是让编译器告诉 Alice 她需要来与您交谈,这样您就可以解决此问题,而不会让客户暴露于 DoDangerousThing 的漏洞。
为什么在 Java 中允许?
不知道,抱歉。
【讨论】:
这样,就像您在示例中所做的那样,只需执行一个空覆盖,就可以轻松地使用标记为内部或私有的类,就像它是公共的一样。这将完全破坏将类标记为公共以外的任何内容的目的。
【讨论】:
internal 与 Java 中的 package private 不同。 DerivedClass 的用户可能没有或无法访问BaseClass 所在的DLL,因此DerivedClass 不能依赖它。包隐私在 Java 中是一个更宽松的概念 - 但在您的示例中,DerivedClass 必须与BaseClass 在同一个包中,因此客户端用户很有可能同时拥有这两个类,因此 Java 允许它。
【讨论】:
The user of DerivedClass may not have or have access to the DLL that BaseClass is in so DerivedClass can't depend on it. 你是不是建议你不能从不同 DLL 中的类继承?
因为否则您将比预期更进一步地暴露 BaseClass 成员。
问题的一个例子是public const int Age。这没关系,因为它只在同一个程序集中公开,所以版本控制是安全的。如果您现在使用继承使类公开,则您将这个 const 字段暴露在程序集之外。如果值被更改,这可能会导致错误。
通常我会在内部创建一个类,这样我就不必担心将来对它的公共接口进行版本控制。我可以随时更改它,只要那个程序集编译它就可以了。如果有人出现并公开曝光它,我现在将不得不永远尊重该公开界面。
【讨论】: