在基类中无法访问受保护的成员 [英] Cannot access protected member in base class

查看:209
本文介绍了在基类中无法访问受保护的成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想想你有下面的代码:

 公共抽象类菜单项
{
保护串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;
}
}




  1. 我真不明白,这个错误背后的逻辑,是的,我已经阅读:
    http://blogs.msdn.com/b/ericlippert/archive/2005/11/09/491031.aspx 结果
    但是我仍然看到它完全根据受保护的访问修饰符的定义不合逻辑。
    我认为这是应该从它被定义相同的类访问是菜单项,并为它的所有派生类! ( ContainerItem 等)


  2. 你将如何访问受保护的成员如 m_Title 按住至菜单项引用(因为多态性设计上的原因)?



解决方案

为什么会出现这种情况?



这不能被争论的答案是因为规范是这么说的




A 保护基类成员在派生类中
访问的只有当出现通过访问派生类类型




但是,让我们探究幕后此限制。



说明



这里发生的是,埃里克利珀描述,您链接到博客张贴同样的事情。您的代码不会等价的:

 公共抽象类菜单项
{
保护串m_Title;
}

公共类ContainerItem:菜单项
{
无效美孚()
{
变种derivedItem =新ContainerItem();
derivedItem.m_Title =测试; //工作正常

VAR baseItem =(菜单项)而得;
baseItem.m_Title =测试; //编译器错误!
}
}



这里的问题的原因是,这件事会发生茎。目前,请忽略这个例子使用的方法,而不是一个领域的事实 - 我们会回来吧。



 公共抽象类菜单项
{
保护无效美孚​​(){}
}

公共类SomeTypeOfItem:菜单项
{
保护覆盖无效美孚(){}
}

公共类ContainerItem:菜单项
{
空栏()
{
VAR baseItem = (菜单项)的东西;
baseItem.Foo(); //#1
}
}



看行#1:如何该编译器知道 baseItem 实际上不是一个 SomeTypeOfItem ?如果是这样,你一定要不能访问!因此,埃里克描述,编译器无法为静态证明的访问始终是合法的,因为它必须禁止这些代码和。



请注意,在某些情况下,例如,如果

  baseItem =(菜单项)新ContainerItem(); 



甚至

  baseItem =(菜单项)这一点; 



编译器确实有足够的信息来证明访问是合法的,但它仍然不会允许代码编译。我想那是因为编译器团队并不认为实施这种特殊情况的处理程序是值得的麻烦(的观点我很同情一个点)。



不过。 ..但...



这是一切都很好的方法(和属性,这是真正的方法) - 什么领域?这个是什么:

 公共抽象类菜单项
{
保护串m_Title;
}

公共类SomeTypeOfItem:菜单项
{
保护的新的字符串m_Title;
}

公共类ContainerItem:菜单项
{
无效美孚()
{
VAR baseItem =(菜单项)的东西;
baseItem.m_Title =我应该被允许改变呢? //#1
}
}



由于字段不能被覆盖,有应该在这里没有歧义,代码应编译并设置 MenuItem.m_Title 不管什么什么类型是。



事实上,我想不出一个的技术的原因,编译器不能做到这一点,但在任何情况下,一个很好的理由:一致性。埃里克本人很可能将能够提供更丰富的解释。



所以,我该怎么办?




你会如何访问受保护的成员一样m_Title同时举行
A参考菜单项(因为多态性设计上的原因)?




您根本无法做到这一点;你将不得不作出成员内部(或公共)。


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;
    }
}

  1. 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 is MenuItem and for all its derived classes! (ContainerItem ,etc)

  2. How would you access the protected members like m_Title while holding a reference to MenuItem (because of Polymorphism design reasons)?

解决方案

Why does this happen?

An answer that cannot be argued with is "because the spec says so":

A protected member of a base class is accessible in a derived class only if the access occurs through the derived class type.

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?

How would you access the protected members like m_Title while holding a reference to MenuItem (because of Polymorphism design reasons)?

You simply cannot do that; you would have to make the members internal (or public).

这篇关于在基类中无法访问受保护的成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆