Você poderia explicar qual é o uso prático da internal
palavra - chave em C #?
Sei que o internal
modificador limita o acesso ao assembly atual, mas quando e em que circunstância devo usá-lo?
Você poderia explicar qual é o uso prático da internal
palavra - chave em C #?
Sei que o internal
modificador limita o acesso ao assembly atual, mas quando e em que circunstância devo usá-lo?
Respostas:
Classes / métodos de utilitário ou auxiliar que você gostaria de acessar de muitas outras classes dentro do mesmo assembly, mas que deseja garantir que o código em outros assemblies não possa acessar.
No MSDN (via archive.org):
Um uso comum do acesso interno é no desenvolvimento baseado em componentes, pois permite que um grupo de componentes coopere de maneira privada sem ser exposto ao restante do código do aplicativo. Por exemplo, uma estrutura para a criação de interfaces gráficas de usuário pode fornecer às classes Control e Form que cooperam usando membros com acesso interno. Como esses membros são internos, eles não são expostos ao código que está usando a estrutura.
Você também pode usar o modificador interno junto com o InternalsVisibleTo
atributo de nível de montagem para criar assemblies "amigos" aos quais é concedido acesso especial às classes internas do assembly de destino.
Isso pode ser útil para a criação de montagens de teste de unidade que podem chamar membros internos da montagem para serem testados. É claro que nenhum outro assembly recebe esse nível de acesso; portanto, quando você libera seu sistema, o encapsulamento é mantido.
Se Bob precisa de BigImportantClass, Bob precisa que as pessoas que possuem o projeto A se inscrevam para garantir que BigImportantClass seja gravado para atender às suas necessidades, testado para garantir que atenda às suas necessidades, seja documentado como atendendo às suas necessidades e que um processo será implementado para garantir que nunca seja alterado, de modo a não atender mais às suas necessidades.
Se uma classe é interna, ela não precisa passar por esse processo, o que economiza orçamento para o Projeto A que eles podem gastar em outras coisas.
O ponto interno não é que isso dificulte a vida de Bob. Isso permite que você controle quais promessas caras o Projeto A está fazendo sobre recursos, tempo de vida, compatibilidade e assim por diante.
Outro motivo para usar interno é se você ofuscar seus binários. O ofuscador sabe que é seguro embaralhar o nome da classe de qualquer classe interna, enquanto o nome da classe pública não pode ser embaralhado, porque isso pode quebrar as referências existentes.
Se você estiver escrevendo uma DLL que encapsula uma tonelada de funcionalidades complexas em uma API pública simples, “interno” é usado nos membros da classe que não devem ser expostos publicamente.
Esconder complexidade (aka encapsulamento) é o principal conceito de engenharia de software de qualidade.
A palavra-chave interna é muito usada quando você está construindo um wrapper sobre código não gerenciado.
Quando você tem uma biblioteca baseada em C / C ++ que deseja DllImport, pode importar essas funções como funções estáticas de uma classe e torná-las internas, para que seu usuário tenha acesso apenas ao seu wrapper e não à API original, portanto não pode mexer com qualquer coisa. Como as funções são estáticas, você pode usá-las em qualquer lugar da montagem, para as várias classes de wrapper necessárias.
Você pode dar uma olhada no Mono.Cairo, é um invólucro da biblioteca do cairo que usa essa abordagem.
Sendo conduzido pela regra "use o modificador mais rigoroso possível", eu uso interno em todos os lugares em que preciso acessar, digamos, o método de outra classe até precisar explicitamente acessá-lo em outro assembly.
Como a interface de montagem geralmente é mais estreita que a soma das interfaces de classes, existem muitos lugares em que eu a uso.
Acho interno muito usado em demasia. você realmente não deve expor certas funcionalidades apenas a determinadas classes que não exporia a outros consumidores.
Na minha opinião, isso quebra a interface, quebra a abstração. Isso não quer dizer que nunca deva ser usado, mas uma solução melhor é refatorar para uma classe diferente ou ser usado de uma maneira diferente, se possível. No entanto, isso nem sempre é possível.
O motivo pelo qual isso pode causar problemas é que outro desenvolvedor pode ser encarregado de criar outra classe no mesmo assembly que o seu. Ter internos diminui a clareza da abstração e pode causar problemas se for mal utilizado. Seria o mesmo problema como se você o tornasse público. A outra classe que está sendo construída pelo outro desenvolvedor ainda é um consumidor, assim como qualquer classe externa. Abstração e encapsulamento de classe não são apenas para proteção de / para classes externas, mas para toda e qualquer classe.
Outro problema é que muitos desenvolvedores pensam que podem precisar usá-lo em outro local da montagem e marcam como interno de qualquer maneira, mesmo que não precisem no momento. Outro desenvolvedor, então, pode pensar que está lá para ser usado. Normalmente, você deseja marcar como privado até ter uma necessidade definitiva.
Mas parte disso pode ser subjetiva, e não estou dizendo que nunca deva ser usado. Basta usar quando necessário.
Vi um interessante outro dia, talvez semana, em um blog que não me lembro. Basicamente, não posso receber crédito por isso, mas achei que poderia ter alguma aplicação útil.
Digamos que você queira que uma classe abstrata seja vista por outra montagem, mas não que alguém possa herdar dela. O Sealed não funcionará porque é abstrato por um motivo, outras classes nesse assembly são herdadas dele. Privado não funcionará porque você pode declarar uma classe Pai em algum lugar da outra montagem.
namespace Base.Assembly { public abstract class Parent { resumo interno vazio SomeMethod (); } // Isso funciona muito bem, pois está na mesma montagem. public class ChildWithin: Parent { substituição interna void SomeMethod () { } } } namespace Another.Assembly { // Kaboom, porque você não pode substituir um método interno public class ChildOutside: Parent { } Teste de classe pública { //Bem private Parent _parent; Teste público () { //Continua tudo bem _parent = new ChildWithin (); } } }
Como você pode ver, ele efetivamente permite que alguém use a classe Parent sem poder herdar.
Este exemplo contém dois arquivos: Assembly1.cs e Assembly2.cs. O primeiro arquivo contém uma classe base interna, BaseClass. No segundo arquivo, uma tentativa de instanciar BaseClass produzirá um erro.
// Assembly1.cs
// compile with: /target:library
internal class BaseClass
{
public static int intM = 0;
}
// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // CS0122
}
}
Neste exemplo, use os mesmos arquivos que você usou no exemplo 1 e altere o nível de acessibilidade do BaseClass para público . Altere também o nível de acessibilidade do membro IntM para interno . Nesse caso, você pode instanciar a classe, mas não pode acessar o membro interno.
// Assembly2.cs
// compile with: /target:library
public class BaseClass
{
internal static int intM = 0;
}
// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // Ok.
BaseClass.intM = 444; // CS0117
}
}
fonte : http://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx
Quando você tem métodos, classes, etc., que precisam estar acessíveis no escopo da montagem atual e nunca fora dela.
Por exemplo, um DAL pode ter um ORM, mas os objetos não devem ser expostos à camada de negócios; toda a interação deve ser feita através de métodos estáticos e passando os parâmetros necessários.
Um uso muito interessante de interno - com o membro interno, é claro, limitado apenas à montagem em que é declarado - está obtendo a funcionalidade "amiga" em algum grau. Um membro amigo é algo que é visível apenas para certas outras assembléias fora da assembléia na qual foi declarado. O C # não possui suporte interno para amigo, no entanto, o CLR sim.
Você pode usar InternalsVisibleToAttribute para declarar um assembly amigo, e todas as referências de dentro do assembly amigo tratarão os membros internos do assembly declarante como públicos no escopo do assembly amigo. Um problema com isso é que todos os membros internos são visíveis; você não pode escolher e escolher.
Um bom uso para InternalsVisibleTo é expor vários membros internos a um conjunto de teste de unidade, eliminando assim as necessidades de soluções complexas de reflexão para testar esses membros. Todos os membros internos visíveis não são um grande problema, no entanto, adotar essa abordagem estraga bastante as interfaces de classe e pode arruinar o encapsulamento dentro do conjunto declarante.
Como regra geral, existem dois tipos de membros:
Redução de ruído, quanto menos tipos você expõe, mais simples é sua biblioteca. A prova de adulteração / segurança é outra (embora o Reflection possa vencer contra ele).
Classes internas permitem limitar a API do seu assembly. Isso tem benefícios, como tornar sua API mais simples de entender.
Além disso, se houver um bug no seu assembly, há menos chances de a correção introduzir uma alteração de quebra. Sem as classes internas, você teria que assumir que mudar os membros públicos de qualquer classe seria uma mudança de quebra. Com classes internas, você pode assumir que a modificação de seus membros públicos apenas quebra a API interna do assembly (e quaisquer assemblies mencionados no atributo InternalsVisibleTo).
Eu gosto de ter encapsulamento no nível da classe e no nível da montagem. Há quem discorde disso, mas é bom saber que a funcionalidade está disponível.
Eu tenho um projeto que usa LINQ-to-SQL para o back-end de dados. Eu tenho dois namespaces principais: Biz e Data. O modelo de dados LINQ reside em Data e está marcado como "interno"; o espaço para nome Biz possui classes públicas que envolvem as classes de dados LINQ.
Então tem Data.Client
, e Biz.Client
; o último expõe todas as propriedades relevantes do objeto de dados, por exemplo:
private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }
Os objetos Biz têm um construtor privado (para forçar o uso de métodos de fábrica) e um construtor interno que se parece com isso:
internal Client(Data.Client client) {
this._client = client;
}
Isso pode ser usado por qualquer uma das classes de negócios na biblioteca, mas o front-end (UI) não tem como acessar diretamente o modelo de dados, garantindo que a camada de negócios sempre atue como intermediária.
Esta é a primeira vez que eu realmente usei internal
muito, e está se mostrando bastante útil.
Há casos em que faz sentido formar membros de classes internal
. Um exemplo poderia ser se você deseja controlar como as classes são instanciadas; digamos que você forneça algum tipo de fábrica para criar instâncias da classe. Você pode criar o construtor internal
, para que a fábrica (que reside no mesmo assembly) possa criar instâncias da classe, mas o código fora desse assembly não possa.
No entanto, não vejo sentido em fazer aulas ou membros internal
sem razões específicas, tão pouco quanto faz sentido public
, ou private
sem razões específicas.
a única coisa em que já usei a palavra-chave interna é o código de verificação de licença no meu produto ;-)
Um uso da palavra-chave interna é limitar o acesso a implementações concretas do usuário de sua montagem.
Se você possui uma fábrica ou algum outro local central para a construção de objetos, o usuário da sua montagem precisa lidar apenas com a interface pública ou a classe base abstrata.
Além disso, construtores internos permitem controlar onde e quando uma classe pública é instanciada.
Que tal este: normalmente é recomendável não expor um objeto de lista a usuários externos de um assembly, mas expor um IEnumerable. Mas é muito mais fácil usar um objeto List dentro do assembly, porque você obtém a sintaxe da matriz e todos os outros métodos de List. Portanto, normalmente tenho uma propriedade interna que expõe uma Lista a ser usada dentro da montagem.
Comentários são bem-vindos sobre essa abordagem.
Lembre-se de que qualquer classe definida como public
será exibida automaticamente no intellisense quando alguém examinar o namespace do seu projeto. Da perspectiva da API, é importante mostrar apenas aos usuários do seu projeto as classes que eles podem usar. Use a internal
palavra-chave para ocultar coisas que eles não deveriam ver.
Se o seu Big_Important_Class
para o Projeto A se destina a ser usado fora do seu projeto, você não deve marcá-lo internal
.
No entanto, em muitos projetos, muitas vezes você tem classes que realmente são destinadas apenas para uso dentro de um projeto. Por exemplo, você pode ter uma classe que mantém os argumentos para uma chamada de encadeamento parametrizada. Nesses casos, você deve marcá-los como internal
se por nenhum outro motivo, a fim de se proteger de uma alteração não intencional da API no futuro.
private
palavra-chave pode ser usada apenas em classes ou estruturas definidas em outra classe ou estrutura. Uma classe definida em um espaço para nome só pode ser declarada public
ou internal
.
A idéia é que, quando você estiver projetando uma biblioteca, apenas as classes destinadas a serem usadas de fora (pelos clientes da sua biblioteca) sejam públicas. Dessa forma, você pode ocultar classes que
etc.
Se você estiver desenvolvendo soluções internas, o uso de elementos internos não é tão importante, eu acho, porque geralmente os clientes terão contato constante com você e / ou acesso ao código. Eles são bastante críticos para os desenvolvedores de bibliotecas.
Quando você tem classes ou métodos que não se encaixam perfeitamente no Paradigma Orientado a Objetos, que fazem coisas perigosas, que precisam ser chamadas de outras classes e métodos sob seu controle e que você não deseja permitir que outras pessoas usem .
public class DangerousClass {
public void SafeMethod() { }
internal void UpdateGlobalStateInSomeBizarreWay() { }
}