问题描述
想想你有下面的代码:
公共抽象类菜单项
{
保护串m_Title ;
保护INT m_Level;
保护的菜单项m_ParentItem;
公共事件ChooseEventHandler m_Click;
保护菜单项(字符串i_Title,诠释i_Level,菜单项i_ParentItem)
{
m_Title = i_Title;
m_Level = i_Level;
m_ParentItem = i_ParentItem;
}
}
和
公共类ContainerItem:菜单项
{
私有列表<&菜单项GT; m_SubMenuItems;
公共ContainerItem(字符串i_Title,诠释i_Level,菜单项i_ParentItem)
:基地(i_Title,i_Level,i_ParentItem)
{
m_SubMenuItems =新的List<菜单项>( );
}
公共字符串GetListOfSubItems()
{
串subItemsListStr =的String.Empty;
的foreach(在m_SubMenuItems菜单项的项目)
{
item.m_Title =测试; //无法访问受保护的成员资格赛
的类型必须是'Ex04.Menus.Delegates.ContainerItem'
}
返回subItemsListStr;
}
}
-
我真不明白,这个错误背后的逻辑,是的,我已经阅读:
的结果
但是我仍然看到它完全根据受保护的访问修饰符的定义不合逻辑。
我认为这是应该从它被定义相同的类访问是菜单项
,并为它的所有派生类! (ContainerItem
等) -
你将如何访问受保护的成员如
m_Title
按住至菜单项
引用(因为多态性设计上的原因)?
为什么会出现这种情况?
这不能被争论的答案是因为规范:
But let's explore this restriction behind the scenes.
Explanation
What happens here is the same thing that Eric Lippert describes in the blog post that you linked to. Your code does the equivalent of this:
public abstract class MenuItem
{
protected string m_Title;
}
public class ContainerItem : MenuItem
{
void Foo()
{
var derivedItem = new ContainerItem();
derivedItem.m_Title = "test"; // works fine
var baseItem = (MenuItem)derived;
baseItem.m_Title = "test"; // compiler error!
}
}
The problem here stems from the fact that this might happen. For the moment, please disregard the fact that this example uses a method instead of a field -- we 'll come back to it.
public abstract class MenuItem
{
protected void Foo() {}
}
public class SomeTypeOfItem : MenuItem
{
protected override void Foo() {}
}
public class ContainerItem : MenuItem
{
void Bar()
{
var baseItem = (MenuItem)something;
baseItem.Foo(); // #1
}
}
Look at line #1: how does the compiler know that baseItem
is not actually a SomeTypeOfItem
? If it is, you certainly must not be able to access Foo
! So, as Eric describes, the compiler is unable to statically prove that the access is always legal and because of that it has to disallow this code.
Note that in some cases, for example if
baseItem = (MenuItem)new ContainerItem();
or even
baseItem = (MenuItem)this;
the compiler does have enough information to prove that the access is legal but it still will not allow the code to compile. I imagine that's because the compiler team is not convinced that implementing such special-case handlers is worth the trouble (a point of view which I am sympathetic to).
But... but...
That's all well and good for methods (and properties, which are really methods) -- what about fields? What about this:
public abstract class MenuItem
{
protected string m_Title;
}
public class SomeTypeOfItem : MenuItem
{
protected new string m_Title;
}
public class ContainerItem : MenuItem
{
void Foo()
{
var baseItem = (MenuItem)something;
baseItem.m_Title = "Should I be allowed to change this?"; // #1
}
}
Since fields cannot be overridden, there should be no ambiguity here and the code should compile and set MenuItem.m_Title
irrespective of what the type of something
is.
Indeed, I cannot think of a technical reason why the compiler couldn't do this, but there is a good reason in any case: consistency. Eric himself would probably be able to provide a richer explanation.
So what can I do?
You simply cannot do that; you would have to make the members internal
(or public
).
这篇关于在基类中无法访问受保护的成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!