这段代码:
abstract class C { protected abstract void F(D d); } class D : C { protected override void F(D d) { } void G(C c) { c.F(this); } }
生成此错误:
无法通过类型为"C"的限定符访问受保护的成员'CF(D)'; 限定符必须是'D'类型(或从中派生)
他们在想什么?(会改变那条规则会破坏某些东西吗?)除了让F公开之外,还有其他方法吗?
编辑:我现在明白为什么会这样(感谢格雷格),但我仍然对理性感到有些困惑; 给定:
class E : C { protected override void F(D d) { } }
为什么不应该 D是能够能够调用EF?
编辑错误消息,所以我可能会在那里输入错误.
这不起作用的原因是因为C#不允许跨层次调用受保护的方法.假设有一个类E
也来自C
:
C / \ D E
然后,您尝试调用方法的引用实际上可能是类型的实例,E
因此该方法可以在运行时解析E.F
.这在C#中是不允许的,因为D
无法调用E
受保护的方法,因为E
它位于层次结构的另一个分支中,即
var d = new D(); var e = new E(); d.G(e); // oops, now this will call E.F which isn't allowed from D
这是有道理的,因为关键字protected
意味着成员" 可以在其类和派生类实例中访问 ",而EF不是D的成员.
"protected"关键字意味着只有从该类型派生的类型和类型才能访问该成员.D与C无关,因此无法访问该成员.
如果您希望能够访问该成员,则有几个选项
把它公之于众
把它做成内部的.这将允许任何类型访问同一程序集中的成员(或者如果你添加朋友的话,可以访问其他程序集)
从C中导出D.
编辑
这种情况在C#规范的第3.5.3节中提到.
不允许这样做的原因是因为它允许跨层次调用.想象一下,除了D之外,还有另一个基类C称为E.如果您的代码可以编译它将允许D访问成员EF这种类型的场景不允许在C#中(我相信 CLR但我不知道t 100%知道).
EDIT2为什么这很糟糕
警告,这是我的看法
现在允许这样做的原因是它很难推断出一个类的行为.访问修饰符的目标是让开发人员准确控制谁可以访问特定方法.想象一下下面的课程
sealed class MyClass : C { override F(D d) { ... } }
考虑如果F是一个有时间关键的功能会发生什么.根据目前的行为,我可以推断出我班级的正确性.毕竟只有两种情况会调用MyClass.F.
它在C中被调用的地方
我在MyClass中显式调用它的位置
我可以检查这些调用,并得出关于MyClass如何运作的合理结论.
现在,如果C#允许跨层次保护访问,我就不能做出这样的保证.任何完全不同的程序集中的任何人都可以来自C.然后他们可以随意调用MyClass.F. 这使我完全无法推断出我班级的正确性.
即使D继承自C,D也无法访问C的受保护成员.D可以访问D的受保护(和私有!)成员,所以如果你把D的另一个实例放在那里而不是C,一切都会工作.但随着格雷格说,C真会是完全不同的东西,因为编译器不知道什么C真的是,它具有防止d访问的东西d实际上可能没有能够访问.
一系列帖子从C#编译器的角度解释了这一点:
为什么我无法从派生类访问受保护的成员
为什么我无法从派生类访问受保护的成员,第二部分:为什么我可以?