A idéia básica é que um "campo" (variável no nível da instância) declarado como protegido provavelmente seja mais visível do que deveria ser e menos "protegido" do que você gostaria. Não há modificador de acesso em C / C ++ / Java / C # que seja equivalente a "acessível apenas por classes filho dentro do mesmo assembly", garantindo assim a capacidade de definir seus próprios filhos que podem acessar o campo em seu assembly, mas não permitir que crianças criadas em outras assembléias tenham o mesmo acesso; O C # possui modificadores internos e protegidos, mas combiná-los torna o acesso "interno ou protegido", não "interno e protegido". Portanto, um campo protegido é acessível a qualquer criança, independentemente de você ter escrito essa criança ou outra pessoa. Protegido é, portanto, uma porta aberta para um hacker.
Além disso, os campos por sua definição praticamente não têm validação inerente à sua alteração. em C #, você pode criar um somente leitura, o que torna os tipos de valor efetivamente constantes e os tipos de referência incapazes de serem reinicializados (mas ainda muito mutáveis), mas é isso. Como tal, mesmo protegidos, seus filhos (nos quais você não pode confiar) têm acesso a esse campo e podem defini-lo como algo inválido, tornando o estado do objeto inconsistente (algo a ser evitado).
A maneira aceita de trabalhar com campos é torná-los privados e acessá-los com uma propriedade e / ou um método getter e setter. Se todos os consumidores da classe precisarem do valor, torne público o publicador (pelo menos). Se apenas crianças precisarem, proteja o getter.
Outra abordagem que responde à pergunta é se perguntar; por que o código em um método filho precisa da capacidade de modificar meus dados de estado diretamente? O que isso diz sobre esse código? Esse é o argumento da "distância vertical". Se houver código em um filho que deva alterar diretamente o estado pai, talvez esse código deva pertencer ao pai em primeiro lugar?