为什么派生类无法从基类访问受保护的getter?

Joh*_*ies 2 c# getter setter encapsulation properties

我有一个这样的课:

public class Base
{
    public Base(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }
    public string PrettyName
    {
        get { return Prettify(Name); }
    }
}
Run Code Online (Sandbox Code Playgroud)

我从中得出:

public class Derived : Base
{
    public Derived(Base b) : base(b.Name) { }
}
Run Code Online (Sandbox Code Playgroud)

Name不应该访问该属性; 逻辑名称只能由PrettyName.访问.所以我以为我会把这个属性做成这样的:

    public string Name { protected get; set; }
Run Code Online (Sandbox Code Playgroud)

但是我得到了这个:

Cannot access protected member 'Name' via a qualifier of type 'Base'; the qualifier must be of type 'Derived' (or derived from it)  
Run Code Online (Sandbox Code Playgroud)

这是为什么?getter应该暴露给基类及其所有子类.我在这里弄错了吗?

Jon*_*eet 5

getter应该暴露给基类及其所有子类.

不,不完全.这不是自动实现的属性问题 - 它是什么protected意思的问题.

访问子类中受保护的成员必须通过该子类(或另一个子类)的实例.你不能Base.Name用于任意 BaseDerived.

从C#规范的3.5.3节:

protected在声明它的类protected internal的程序文本之外访问实例成员时,并且当在声明它的程序的程序文本之外访问实例成员时,访问必须在派生的类声明中进行.来自声明它的类.此外,需要通过该派生类类型的实例或从其构造的类类型进行访问.此限制可防止一个派生类访问protected其他派生类的成员,即使这些成员是从同一基类继承的.

一个简单的解决方案是重载构造函数Base:

protected Base(Base b) : this(b.Name)
{
}
Run Code Online (Sandbox Code Playgroud)

然后在Derived:

public Derived(Base b) : base(b) { }
Run Code Online (Sandbox Code Playgroud)

此时,您可以将Namesetter设为私有 - 或者更好,使其完全只读:

private readonly string name;
public string Name { get { return name; } }
Run Code Online (Sandbox Code Playgroud)