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

class MyBase
{
    protected object PropertyOfBase { get; set; }
}

class MyType : MyBase
{
    void MyMethod(MyBase parameter)
    {
        // I am looking for:
        object p = parameter.PropertyOfBase;  // error CS1540: Cannot access protected member 'MyBase.PropertyOfBase' via a qualifier of type 'MyBase'; the qualifier must be of type 'MyType' (or derived from it)
    }
}

Есть ли способ получить защищенное свойство параметра типа из расширяющегося типа без отражения? Поскольку расширяющийся класс знает свойство через его базовый тип, это имело бы смысл, если это возможно.

Ответ 1

Нет, вы не можете этого сделать.

Вам разрешен доступ только к защищенным членам объектов типа доступа (или полученным из него). Здесь мы не знаем, имеет ли параметр тип MyType или SomeOtherCompletelyDifferentType.

EDIT: соответствующий бит спецификации С# 3.0 - это раздел 3.5.3:

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

Ответ 2

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

class MyBase
{
    protected object PropertyOfBase { get; set; }

    protected static object GetPropertyOfBaseOf(MyBase obj) 
    {
        return obj.PropertyOfBase;
    }
}

class MyType : MyBase
{
    void MyMethod(MyBase parameter)
    {
        object p = GetPropertyOfBaseOf(parameter);
    }
}

Ответ 3

Там хорошая причина, по которой вы не можете этого сделать. Предположим, кто-то пишет:

class Other : MyBase { }

new MyType().MyMethod(new Other());

Если язык разрешил то, о чем вы просите, вы можете нарушить предполагаемые инварианты Other, изменив значение PropertyOfBase.

Ответ 4

Я думаю, вы должны спросить себя, есть ли лучший способ сделать то, что вы хотите сделать. Вы хотите, чтобы PropertyOfBase действовал как открытый в контексте MyType.MyMethod(), но для защиты во всех других ситуациях. Почему?

Ответ 5

Защищенное свойство доступно только экземпляру производного класса, а не экземплярам производных классов.

Есть разница, и имеет смысл, защищенные члены не должны отказываться от своего значения ни к какому другому экземпляру, даже к экземпляру, полученному из того же типа.

(Отредактировано, немного привязано к языку!)