Почему производный класс не может получить доступ к защищенному геттеру из базового класса?

У меня есть такой класс:

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)  

Это почему? Геттер должен быть доступен базовому классу и всем его дочерним классам. Я здесь что-то не так?


person John NoCookies    schedule 28.11.2013    source источник


Ответы (2)


Геттер должен быть доступен базовому классу и всем его дочерним классам.

Нет, не совсем. Дело не в автоматически реализуемых свойствах, а в том, что означает protected.

Доступ к защищенному элементу внутри подкласса должен осуществляться через экземпляр этого подкласса (или другого подкласса). Вы не можете использовать Base.Name вместо произвольного Base в Derived.

Из раздела 3.5.3 спецификации С#:

Когда доступ к члену экземпляра protected осуществляется за пределами текста программы класса, в котором он объявлен, и когда доступ к члену экземпляра protected internal осуществляется за пределами текста программы программы, в которой он объявлен, доступ должен иметь место в объявлении класса. который происходит от класса, в котором он объявлен. Кроме того, доступ должен осуществляться через экземпляр этого типа производного класса или типа класса, созданного на его основе. Это ограничение не позволяет одному производному классу получить доступ к protected членам других производных классов, даже если эти члены унаследованы от одного и того же базового класса.

Простым решением было бы перегрузить конструктор в Base:

protected Base(Base b) : this(b.Name)
{
}

затем в Derived:

public Derived(Base b) : base(b) { }

В этот момент вы также можете сделать сеттер Name закрытым или, что еще лучше, сделать его полностью доступным только для чтения:

private readonly string name;
public string Name { get { return name; } }
person Jon Skeet    schedule 28.11.2013

Это любопытный способ создания производного конструктора. Почему нет:

public class Derived : Base
{
    public Derived(string name) : base(name)
    { }

    public void Test()
    {
        //here, it's perfectly ok to access the protected Name.
    }
}
person David S.    schedule 28.11.2013
comment
Поскольку код примера упрощен, и то, чего я пытаюсь добиться с помощью реального кода, — это копирование всех свойств b (это больше, чем просто имя) в новый объект. - person John NoCookies; 28.11.2013