我有一个这样的课程:
public class Base
{
public Base(string name)
{
this.Name = name;
}
public string Name { get; set; }
public string PrettyName
{
get { return Prettify(Name); }
}
}
我从中得出:
public class Derived : Base
{
public Derived(Base b) : base(b.Name) { }
}
不应访问Name
属性;逻辑名称只能由PrettyName
访问。所以我以为我会把这个属性做成这样的:
public string Name { protected get; set; }
但我得到了这个:
Cannot access protected member 'Name' via a qualifier of type 'Base'; the qualifier must be of type 'Derived' (or derived from it)
为什么? getter应该暴露给基类及其所有子类。我在这里弄错了吗?
答案 0 :(得分:5)
getter应该暴露给基类及其所有子类。
不,不完全。这不是自动实现的属性问题 - 这是protected
的意思。
访问子类中的受保护成员必须通过该子类(或另一个子类)的实例。您无法在Base.Name
中使用Base
作为任意 Derived
。
来自C#规范的第3.5.3节:
当在声明它的类的程序文本之外访问
protected
实例成员时,以及在程序的程序文本之外访问protected internal
实例成员时声明,访问必须在一个类声明中发生,该声明派生自声明它的类。此外,需要通过该派生类类型的实例或从其构造的类类型进行访问。此限制可防止一个派生类访问其他派生类的protected
成员,即使成员是从同一基类继承的。
一个简单的解决方案是重载Base
中的构造函数:
protected Base(Base b) : this(b.Name)
{
}
然后在Derived
:
public Derived(Base b) : base(b) { }
此时,您可以将Name
setter设为私有 - 或者更好,将其设置为完全只读:
private readonly string name;
public string Name { get { return name; } }
答案 1 :(得分:0)
这是制作派生构造函数的一种奇怪方式。为什么不:
public class Derived : Base
{
public Derived(string name) : base(name)
{ }
public void Test()
{
//here, it's perfectly ok to access the protected Name.
}
}