为什么我不能像这样访问 C# 受保护成员?
此代码:
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 之外,还有其他方法可以解决这个问题吗?
编辑:我现在明白了为什么会这样(谢谢 Greg)但我仍然对理性感到有点困惑; 给出:
class E : C
{
protected override void F(D d) { }
}
为什么 D 不应该能够调用 EF?
错误消息已被编辑,因此我可能在那里输入了拼写错误。
This code:
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);
}
}
Generates this error:
Cannot access protected member 'C.F(D)' via a qualifier of type 'C'; the qualifier must be of type 'D' (or derived from it)
What in the world were they thinking? (Would altering that rule break something?) And is there a way around that aside from making F public?
Edit: I now get the reason for why this is (Thanks Greg) but I'm still a bit perplexed as to the rational; given:
class E : C
{
protected override void F(D d) { }
}
Why shouldn't D be able to be able to call E.F?
The error message is edited so I might have put a typo in there.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这不起作用的原因是 C# 不允许跨层次调用受保护的方法。 假设有一个类
E
也派生自C
:那么您尝试调用该方法的引用实际上可能是
E< 类型的实例/code> 因此该方法可以在运行时解析为
EF
。 这在 C# 中是不允许的,因为D
无法调用E
的受保护方法,因为E
位于层次结构的另一个分支中,即这使得这是有道理的,因为关键字
protected
表示成员“可在以下范围内访问:它的类和派生类实例”并且 EF 不是 D 的成员。The reason this doesn't work is because C# doesn't allow cross-hierarchy calling of protected methods. Say there was a class
E
that also derived fromC
:Then the reference you're trying to call the method on could actually be an instance of type
E
and thus the method could resolve at runtime toE.F
. This is not permitted in C# asD
cannot callE
's protected methods, becauseE
is in another branch of the hierarchy, i.e.This makes sense because the keyword
protected
means the member "is accessible within its class and by derived class instances" and E.F is not a member of D.“protected”关键字意味着只有一个类型和从该类型派生的类型才能访问该成员。 D 与 C 没有关系,因此无法访问该成员。
如果您希望能够访问该成员,您有几个选择:
编辑
这种情况在 C# 规范的第 3.5.3 节中提到。
不允许这样做的原因是它允许跨层次结构调用。 想象一下,除了 D 之外,还有另一个名为 E 的 C 基类。如果您的代码可以编译,它将允许 D 访问成员 EF 这种情况在 C# 中是不允许的(我相信 CLR,但我不是 100% 知道)。
EDIT2 为什么这是不好的
警告,这是我的观点
现在允许这样做的原因是它使得很难推理一个类的行为。 访问修饰符的目标是让开发人员准确控制谁可以访问特定方法。 想象一下下面的类
考虑如果 F 是一个对时间要求严格的函数会发生什么。 通过当前的行为,我可以推断出我的类的正确性。 毕竟只有两种情况会调用 MyClass.F。
我可以检查这些调用并得出有关 MyClass 如何运行的合理结论。
现在,如果 C# 确实允许跨层次结构的受保护访问,我无法做出这样的保证。 完全不同的程序集中的任何人都可以从 C 来并派生。然后他们可以随意调用 MyClass.F。 这使得完全不可能推断我的课程的正确性。
The "protected" keyword means that only a type and types that derive from that type can access the member. D has no relationship to C therefore cannot access the member.
You have a couple of options if you want to be able to access that member
EDIT
This scenario is called out in section 3.5.3 of the C# spec.
The reason this is not allowed is because it would allow for cross hierarchy calls. Imagine that in addition to D, there was another base class of C called E. If your code could compile it would allow D to access the member E.F. This type of scenario is not allowed in C# (and I believe the CLR but I don't 100% know).
EDIT2 Why this is bad
Caveat, this is my opinion
The reason this is now allowed is it makes it very difficult to reason about the behavior of a class. The goal of access modifiers is to give the developer control over exactly who can access specific methods. Imagine the following class
Consider what happens if F is a somewhat time critical function. With the current behavior I can reason about the correctness of my class. After all there are only two cases where MyClass.F will be called.
I can examine these calls and come to a reasonable conclusion about how MyClass functions.
Now, if C# does allow cross hierarchy protected access I can make no such guarantee. Anyone in a completely different assembly can come by and derive from C. Then they can call MyClass.F at will. This makes it completely impossible to reason about the correctness of my class.
即使 D 继承自 C,D 也无法访问 C 的受保护成员。 D 可以访问 D 的受保护(和私有!)成员,因此如果您将 D 的另一个实例而不是 C 放在那里,一切都会正常。 但正如 Greg 所说,C 确实可能是完全不同的东西,并且因为编译器不知道 C 到底是什么,所以它必须阻止 D 访问 D 实际上可能无法访问的东西。
一系列帖子从 C# 编译器的角度解释了这一点:
Even though D is inherits from C, D cannot access C's protected members. D can access D's protected (and private!) members, so if you put another instance of D in there instead of C everything would work. But as Greg stated, C could really be something completely different, and because the compiler doesn't know what C really is, it has to prevent D from accessing something D may not actually be able to access.
A series of posts explaining this from the C# compiler's perspective:
可以通过使用静态受保护方法来绕过此限制:
从安全角度来看这并不完美(任何人都可以从
C
派生),但如果您关心的是隐藏方法F
从类C
的公共接口来看,这个技巧可能很有用。This limitation can be bypassed by using a static protected method:
This isn't perfect from security point of view (anyone can derive from
C
), but if all you care about is hiding methodF
from the public interface of the classC
, this trick may be useful.简而言之:访问实例的受保护成员将被视为公共访问,即使您尝试从派生类中执行此操作。 因此,它被否认。
这里和那里有很多答案,但没有一个让我清楚“为什么我无法从孩子访问父类的受保护成员”。 以上是我在阅读这些令人困惑的答案后再次查看我的代码后所理解的。
示例:
您认为您可以访问
p.foo
因为您位于子类中,但您是从实例访问它,这就像公共访问,所以它是否认。您可以从类内部访问受保护的成员,而不是从实例(是的,我们知道这一点):
最后,为了完整起见,您实际上可以访问实例的
>protected
甚至private
成员(仅当您在同一个类中这样做时):Simply put: accessing an instance's protected member is taken as a public access, even if you try to do so from within a derived class. Hence, it's denied.
There are many answers here and there, but none of them made it clear to me "why I can't access the protected members of a parent class from a child". That above is what I understood after looking at my code again after reading these confusing answers.
Example:
You'd think you'd have access to
p.foo
because you're inside a child class, but you're accessing it from a instance, and that's like a public access, so it's denied.You're allowed to access
protected
members from within the class, not from an instance (yes, we know this):Finally, for the sake of completeness, you are actually able to access an instance's
protected
and evenprivate
members only if you're doing so within the same class:为了理解为什么这种行为有意义,让我们考虑一下为什么在面向对象的编程语言中需要访问修饰符。 我们需要它们来限制特定类成员的使用范围。 这反过来又简化了对用法的搜索。
总结一下:
因此,如果编译器允许以所描述的方式从超类调用受保护的方法,我们最终可能会跨层次调用受保护的方法,如 这个答案。 在这种情况下,我们必须搜索定义该成员的最父类的所有子类。 这会扩大范围。
附言。 Java 中也实现了相同的行为。
To understand why this kind of behavior makes sense let's consider why we need access modifiers at all in object oriented programming languages. We need them to limit a scope where a particular class member can be used. And that in turn simplifies searching for the usages.
To summarize:
So if the compiler allowed to call protected method from superclass in the described way we could end up with cross-hierarchy calling of protected methods as described in this answer. And in such situation one had to search through all the children of the most parent class that defines the member. And that would increase the scope.
PS. The same behavior is implemented in Java.
对的,这是可能的。 我们很可能很快就会有这样的例子。
为此,您必须执行以下操作:
公共部分类 CustomAppointmentEditDialog : EditAppointmentDialog
{
私有 RadComboBox cmbShowTimeAs = null;
在上面的代码中,我添加了一个附加复选框,并将约会的状态(显示时间为)设置为“暂定”(如果未选中)或“忙碌”(如果选中)。 访问组合框的奇怪方式是因为它当前是私有的。 这将在即将发布的 2009 年第一季度版本中进行更改。
private IEditAppointmentDialog AppointmentEditDialog = null;
我希望这有帮助。 如果您还有其他问题,请随时给我回信。
Yes, it is possible. We will most probably have such an example very soon.
To do that you must do the following:
public partial class CustomAppointmentEditDialog : EditAppointmentDialog
{
private RadComboBox cmbShowTimeAs = null;
In the above code I have added an additional check box and set the status (show time as) of the appointment to Tentative if it is unchecked or to Busy if it is checked. The strange way of accessing the combo box is because it is private currently. This will be changed for the upcoming Q1 2009 release.
private IEditAppointmentDialog appointmentEditDialog = null;
I hope this helps. Do not hesitate to write me back if you have further questions.