Защищенные члены С#, доступные через переменную базового класса

Это может показаться скорее новичком, но вы можете объяснить, почему метод Der.B() не может получить доступ к защищенному Foo через переменную Base class? Это выглядит странно для меня:

public class Base
{
    protected int Foo;
}

public class Der : Base
{
    private void B(Base b) { Foo = b.Foo; } // Error: Cannot access protected member

    private void D(Der d) { Foo = d.Foo; } // OK
}

Спасибо!

Ответ 1

Это часто задаваемый вопрос. Чтобы понять, почему это незаконно, подумайте о том, что может пойти не так.

Предположим, что у вас был другой производный класс Frob, полученный из Base. Теперь вы передаете экземпляр Frob в Der.B. Должны ли вы иметь доступ к Frob.Foo из Der.B? Нет, абсолютно нет. Frob.Foo защищен; он должен быть доступен только из Frob и подклассов Frob. Der не является Frob и не является подклассом Frob, поэтому он не получает доступа к защищенным членам Frob.

Если это неясно, см. мою статью на эту тему:

http://blogs.msdn.com/ericlippert/archive/2005/11/09/491031.aspx

Ответ 2

В B вы пытаетесь получить доступ к защищенному члену другого класса. Тот факт, что вы наследуете от этого класса, не имеет значения. В D вы получаете доступ к защищенному члену базового класса вашего текущего класса. В этом контексте вы можете получить доступ к чему-либо из Der и защищенным членам типа, из которого он наследуется.

Ответ 3

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

В:

private void B(Base b) { Foo = b.Foo; }

Вы пытаетесь получить доступ к защищенному члену, к которому ваш экземпляр Der не имеет доступа. Он будет иметь доступ только к нему, если бы это был базовый класс вашего текущего экземпляра Der (this).

private void D(Der d) { Foo = d.Foo; } // OK

Прекрасно работает, потому что вы проходите через Der для доступа к нему. Защищенный метод классов.

Ответ 4

Вы можете обойти это ограничение, объявив статический метод в базовом классе:

public class Base
{
    protected int Foo;

    protected static int GetFoo(Base b)
    {
        return b.Foo;
    }
}

public class Der : Base
{
    private void B(Base b) { Foo = GetFoo(b); } // OK
}

Ответ 5

В сценарии, который вы пытаетесь, вы захотите использовать "internal" для int Foo.