Há muito código em um de nossos projetos que se parece com isso:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (s == null)
{
return "Foo";
}
return $({s}Foo);
}
}
Existe algum motivo explícito para fazer isso além de "é mais fácil tornar o tipo público posteriormente?"
Eu suspeito que isso só importa em casos extremos muito estranhos (reflexo no Silverlight) ou não.
return s + "Foo";
? O+
operador não se importa com cadeias nulas ou vazias.Respostas:
ATUALIZAÇÃO: Esta questão foi o assunto do meu blog em setembro de 2014 . Obrigado pela ótima pergunta!
Há um debate considerável sobre essa questão, mesmo dentro da própria equipe do compilador.
Primeiro, é aconselhável entender as regras. Um membro público de uma classe ou estrutura é um membro acessível a qualquer coisa que possa acessar o tipo de contenção . Portanto, um membro público de uma classe interna é efetivamente interno.
Então agora, dada uma classe interna, os membros que você deseja acessar na assembléia devem ser marcados como públicos ou internos?
Minha opinião é: marque esses membros como públicos.
Eu uso "público" para significar "este membro não é um detalhe de implementação". Um membro protegido é um detalhe de implementação; há algo sobre isso que será necessário para fazer uma classe derivada funcionar. Um membro interno é um detalhe de implementação; outra coisa interna a esta montagem precisa do membro para funcionar corretamente. Um membro público diz "esse membro representa a funcionalidade documentada chave fornecida por esse objeto".
Basicamente, minha atitude é: suponha que decidi transformar essa classe interna em pública. Para fazer isso, quero mudar exatamente uma coisa : a acessibilidade da classe. Se transformar uma classe interna em uma classe pública significa que eu também preciso transformar um membro interno em um membro público, esse membro fazia parte da área pública da classe e deveria ter sido público em primeiro lugar.
Outras pessoas discordam. Há um contingente que diz que eles querem poder dar uma olhada na declaração de um membro e saber imediatamente se ela será chamada apenas a partir do código interno.
Infelizmente, isso nem sempre funciona bem; por exemplo, uma classe interna que implementa uma interface interna ainda precisa ter os membros de implementação marcados como públicos, porque fazem parte da superfície pública da classe .
fonte
public
é muito convincente. No entanto, acho que "nem sempre funciona bem ..." para ser especialmente poderoso. A perda de consistência desvaloriza todos os benefícios "de relance". Usarinternal
dessa maneira significa criar deliberadamente intuições que às vezes estão erradas. Ter uma intuição quase certa é IMO uma coisa horrível para se programar.Se a classe for
internal
, não importa do ponto de vista da acessibilidade se você marca um métodointernal
oupublic
. No entanto, ainda é bom usar o tipo que você usaria se a classe fossepublic
.Enquanto alguns disseram que isso facilita as transições de
internal
parapublic
. Também serve como parte da descrição do método.Internal
os métodos normalmente são considerados inseguros para acesso irrestrito, enquanto ospublic
métodos são considerados (principalmente) jogos gratuitos.Ao usar
internal
oupublic
como faria em umapublic
classe, você garante que está comunicando qual estilo de acesso é esperado, além de facilitar o trabalho necessário para tornar a classepublic
no futuro.fonte
Costumo marcar meus métodos em classes internas como públicos, em vez de internos, pois a) realmente não importa eb) eu uso interno para indicar que o método é interno de propósito (há alguma razão pela qual não quero expor isso Portanto, se eu tiver um método interno, realmente preciso entender o motivo pelo qual ele é interno antes de alterá-lo para público, enquanto que, se estiver lidando com um método público em uma classe interna, realmente tenho que pensar por que o método A classe é interna e não o motivo pelo qual cada método é interno.
fonte
Eu suspeito que "é mais fácil tornar o tipo público mais tarde?" é isso.
As regras de escopo significam que o método só será visível como
internal
- portanto, não importa se os métodos estão marcadospublic
ouinternal
.Uma possibilidade que vem à mente é que a classe era pública e posteriormente foi alterada para
internal
e o desenvolvedor não se deu ao trabalho de alterar todos os modificadores de acessibilidade do método.fonte
Em alguns casos, também pode ser que o tipo interno implemente uma interface pública, o que significaria que qualquer método definido nessa interface ainda precisaria ser declarado como público.
fonte
É o mesmo, o método público será realmente marcado como interno, pois está dentro de uma classe interna, mas possui uma vantagem (como você convidou); se você quiser marcar a classe como pública, precisará alterar menos código.
fonte
internal
diz que o membro só pode ser acessado de dentro do mesmo assembly. Outras classes nessa montagem podem acessar ointernal public
membro, mas não poderiam acessar umprivate
ouprotected
membro,internal
ou não.fonte
internal
vez depublic
, sua visibilidade não mudaria. Acredito que é sobre isso que o OP está perguntando.Na verdade, eu lutei com isso hoje. Até agora, eu teria dito que todos os métodos deveriam ser marcados com
internal
se a classe fosseinternal
e consideraria qualquer outra coisa simplesmente como mau código ou preguiça, especialmente no desenvolvimento da empresa; no entanto, eu tive que subclassificar umapublic
classe e substituir um de seus métodos:O método DEVE ser
public
e me fez pensar que não há realmente nenhum ponto lógico para definir métodos, ainternal
menos que eles realmente devam ser, como disse Eric Lippert.Até agora, eu nunca parei para pensar sobre isso, apenas aceitei, mas depois de ler o post de Eric, isso realmente me fez pensar e depois de muita deliberação, faz muito sentido.
fonte
Existe uma diferença. Em nosso projeto, tornamos muitas classes internas, mas fazemos testes de unidade em outra montagem e, em nossas informações de montagem, usamos InternalsVisibleTo para permitir que o assembly UnitTest chame as classes internas. Eu notei que se a classe interna tiver um construtor interno, não conseguiremos criar uma instância usando Activator.CreateInstance no assembly de teste de unidade por algum motivo. Mas se mudarmos o construtor para público, mas a classe ainda for interna, funcionará bem. Mas acho que esse é um caso muito raro (como Eric disse no post original: Reflexão).
fonte
Eu acho que tenho uma opinião adicional sobre isso. No começo, eu estava pensando em como faz sentido declarar algo para o público em uma classe interna. Então acabei aqui, lendo que poderia ser bom se você decidir mudar a classe para público mais tarde. Verdade. Então, um padrão se formou em minha mente: se não alterar o comportamento atual, seja permissivo e permita coisas que não fazem sentido (e não prejudicam) no estado atual do código, mas mais tarde, se você altere a declaração da classe.
Como isso:
De acordo com o "padrão" que mencionei acima, isso deve estar perfeitamente correto. Segue a mesma ideia. Ele se comporta como um
private
método, pois você não pode herdar a classe. Mas se você excluir asealed
restrição, ela ainda é válida: as classes herdadas podem ver esse método, que é absolutamente o que eu queria alcançar. Mas você recebe um aviso:,CS0628
ouCA1047
. Ambos são sobre não declararprotected
membros em umasealed
classe. Além disso, encontrei total acordo sobre o que não faz sentido: aviso de 'membro protegido em classe selada' (classe única)Então, após esse aviso e a discussão vinculados, decidi tornar tudo interno ou menos, em uma classe interna, porque isso conforma mais esse tipo de pensamento, e não misturamos "padrões" diferentes.
fonte