Consider you have the following code:
public abstract class MenuItem
{
protected string m_Title;
protected int m_Level;
protected MenuItem m_ParentItem;
public event ChooseEventHandler m_Click;
protected MenuItem(string i_Title, int i_Level, MenuItem i_ParentItem)
{
m_Title = i_Title;
m_Level = i_Level;
m_ParentItem = i_ParentItem;
}
}
and
public class ContainerItem : MenuItem
{
private List<MenuItem> m_SubMenuItems;
public ContainerItem(string i_Title, int i_Level, MenuItem i_ParentItem)
:base(i_Title, i_Level, i_ParentItem)
{
m_SubMenuItems = new List<MenuItem>();
}
public string GetListOfSubItems()
{
string subItemsListStr = string.Empty;
foreach (MenuItem item in m_SubMenuItems)
{
item.m_Title = "test"; // Cannot access protected member the qualifier
must be of type 'Ex04.Menus.Delegates.ContainerItem'
}
return subItemsListStr;
}
}
I really do not understand the logic behind this error, and yes I have already read: http://blogs.msdn.com/b/ericlippert/archive/2005/11/09/491031.aspx
But I still see it totally illogical according to the definition of Protected Access modifier. I see it as should be accessible from the same class where it was defined which isMenuItem
and for all its derived classes! (ContainerItem
,etc)How would you access the protected members like
m_Title
while holding a reference toMenuItem
(because of Polymorphism design reasons)?
Why does this happen?
An answer that cannot be argued with is "because the spec says so":
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:
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.
Look at line #1: how does the compiler know that
baseItem
is not actually aSomeTypeOfItem
? If it is, you certainly must not be able to accessFoo
! 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
or even
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:
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 ofsomething
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
(orpublic
).protected
does mean that the derived class can access it, however, the derived class can access the property of it's own instance. In your example, you can accessthis.m_Title
since that belongs to the instance itself, but you are attempting to access the protected member of another instance (i.e. the instance in the listm_SubMenuItems
).You need getter and setter methods to access it the way you're trying to.
Hopefully this makes it clearer: