9

(这个问题是C# 访问派生类中受保护成员的后续问题)

我有以下代码片段:

public class Fox
{
    protected string FurColor;
    private string furType;

    public void PaintFox(Fox anotherFox)
    {
        anotherFox.FurColor = "Hey!";
        anotherFox.furType = "Hey!";
    }
}

public class RedFox : Fox
{
    public void IncorrectPaintFox(Fox anotherFox)
    {
        // This one is inaccessible here and results in a compilation error.
        anotherFox.FurColor = "Hey!";
    }

    public void CorrectPaintFox(RedFox anotherFox)
    {
        // This is perfectly valid.
        anotherFox.FurColor = "Hey!";
    }
}
  • 现在,我们知道私有和受保护的字段是私有的,并且受类型保护,而不是实例保护。

  • 我们也知道访问修饰符应该在编译时起作用。

  • 所以,问题来了——为什么我不能访问类实例的FurColor字段?FoxRedFox RedFox派生自Fox,因此编译器知道它可以访问相应的受保护字段。

  • 此外,正如您在 中看到的,我可以访问类实例CorrectPaintFox的受保护字段。那么,为什么我不能对类实例有同样的期望呢?RedFoxFox

4

2 回答 2

5

原因很简单:

public void IncorrectPaintFox(Fox anotherFox)
{
    anotherFox = new BlueFox();

    // This one is inaccessible here and results in a compilation error.
    anotherFox.FurColor = "Hey!";
}

现在您没有从 内部访问受保护的字段BlueFox,因此由于编译器不知道运行时类型是什么,它必须始终使其成为错误。

于 2012-05-18T20:19:14.067 回答
2

为了稍微扩展已接受的答案,编译器强制执行此规则的原因,而不是 PHP 具有更宽松的含义protected,是因为允许您想要允许的访问将有可能破坏类的不变量,通过绕过其定义的保护级别。(当然,这总是可能的,例如通过反射,但编译器至少让它很难偶然做到)。

问题在于,仅仅知道某个对象是 aFox并不能使您安全地与其内部工作交互,因为它在运行时可能实际上不是a Fox。考虑这些类:

public class Fox
{
  protected Color FurColor;
}

public class RedFox
{
  public RedFox () 
  { 
    this.FurColor = Color.Red; 
  }
}

public class ArcticFox
{
  public ArcticFox () 
  { 
    this.FurColor = Color.White; 
  }
}  

您要求的是编译器允许以下方法,假设它是在RedFox类上定义的:

public void PaintFoxRed ( Fox fox )
{
    fox.FurColor = Color.Red;
}

但如果这是合法的,我可以这样做:

RedFox a = new RedFox();
Fox b = new ArcticFox();
a.PaintFoxRed(b);

ArcticFox尽管班级本身只允许自己是白色的,但我现在是红色的。

于 2012-05-18T20:57:35.137 回答