Qual é o motivo real para impedir o acesso de membros protegidos através de uma classe base / irmão?
Descobri recentemente que um método em uma classe derivada pode acessar apenas os membros da instância protegida da classe base por meio de uma instância da classe derivada (ou de uma de suas subclasses):
class Base
{
protected virtual void Member() { }
}
class MyDerived : Base
{
// error CS1540
void Test(Base b) { b.Member(); }
// error CS1540
void Test(YourDerived yd) { yd.Member(); }
// OK
void Test(MyDerived md) { md.Member(); }
// OK
void Test(MySuperDerived msd) { msd.Member(); }
}
class MySuperDerived : MyDerived { }
class YourDerived : Base { }
Consegui contornar essa restrição adicionando um método estático à classe base, já que os métodos da Base têm permissão para acessar Base.Member e MyDerived pode chamar esse método estático.
Ainda não entendi o motivo dessa limitação. Eu vi algumas explicações diferentes, mas elas não conseguem explicar por que MyDerived.Test () ainda tem permissão para acessar MySuperDerived.Member.
A explicação de princípio:'Protegido' significa que só é acessível para essa classe e suas subclasses. YourDerivedpoderia Sobrescreva Member (), criando um novo método que só deve estar acessível para YourDerived e suas subclasses. MyDerived não pode chamar o yd.Member () substituído porque não é uma subclasse de YourDerived, e ele não pode chamar b.Member () porque b pode realmente ser uma instância de YourDerived.
OK, mas por que MyDerived pode chamar msd.Member ()? MySuperDerived poderia substituir Member (), e essa substituição deve ser acessível apenas para MySuperDerived e suas subclasses, certo?
Você realmente não sabe até a execução se você está chamando um membro substituído ou não. E quando o membro é um campo, ele não pode ser substituído de qualquer maneira, mas o acesso ainda é proibido.
A explicação pragmática:Outras classes podem adicionar invariantes que sua classe não conhece e você deve usar sua interface pública para poder manter essas invariantes. Se MyDerived pudesse acessar diretamente membros protegidos de YourDerived, isso poderia quebrar essas invariantes.
Minha mesma objeção se aplica aqui. MyDerived não sabe quais invariantes MySuperDerived pode adicionar - pode ser definido em um assembly diferente por um autor diferente - então por que MyDerived pode acessar seus membros protegidos diretamente?
Tenho a impressão de que essa limitação de tempo de compilação existe como uma tentativa equivocada de resolver um problema que realmente só pode ser resolvido em tempo de execução. Mas talvez eu esteja perdendo alguma coisa. Alguém tem um exemplo de um problema que seria causado por deixar MyDerived acessar membros protegidos da Base através de uma variável do tipo YourDerived ou Base, mas faznão já existe ao acessá-los através de uma variável do tipo MyDerived ou MySuperDerived?
-
UPDATE: Eu sei que o compilador está apenas seguindo a especificação da linguagem; o que eu quero saber é o propósito daquela parte da especificação. Uma resposta ideal seria: "Se MyDerived pudesse chamar YourDerived.Member (), $ NIGHTMARE aconteceria, mas isso não pode acontecer ao chamar MySuperDerived.Member () porque $ ITSALLGOOD."