C#
11 - O
modificador file
![]() |
Hoje veremos o novo recurso do C# 11 : o modificador file. |
Uma das novidades
do C#11 é a inclusão do novo recurso de tipos com escopo de arquivo
através do modificador file.
Assim foi introduzido o novo modificador file que pode ser aplicado a qualquer definição de tipo para restringir o seu uso ao arquivo atual. Desta forma podemos ter várias classes com o mesmo nome em um único projeto.
Para ilustrar o uso deste recurso vamos criar um projeto Console chamado AppConsole1 usando o Visual Studio 2022 Preview com o .NET 7 RC 2 instalado.
Neste projeto vamos criar a mesma classe Resposta em dois arquivos distintos : Arquivo1.cs e Arquivo2.cs
1- Arquivo1.cs
namespace AppConsole1; file static class Resposta{ internal static string GetFileScopeSecreto() => "Resposta do Arquivo1.cs"; } static class ClasseInternaArquivo1{ internal static string GetString() => Resposta.GetFileScopeSecreto(); } |
Aqui usamos o modificador file na classe Resposta em Arquivo1.
2- Arquivo2.cs
namespace AppConsole1; file static class Resposta{ internal static string GetFileScopeSecreto() => "Resposta do Arquivo2.cs"; } static class ClasseInternaArquivo2{ internal static string GetString() => Resposta.GetFileScopeSecreto(); } |
Aqui usamos o modificador file em uma classe com o nome Resposta(o mesmo nome usado em Arquivo1) em Arquivo2.
A seguir na classe Program vamos incluir o código abaixo:
using
AppConsole1; using static System.Console; WriteLine(ClasseInternaArquivo1.GetString()); WriteLine(ClasseInternaArquivo2.GetString()); ReadKey(); |
Executando o projeto teremos o resultado a seguir:
Desta forma vemos que os tipos com o modificador file podem ser acessados indiretamente fora de seu arquivo de origem não havendo conflitos de nomes.
No código acima,
contamos com as classes internas
ClasseInternaArquivo1
e
ClasseInternaArquivo2
para executar ambas as classes
Resposta na classe Program.
A classe Resposta onde usamos o modificador file também pode ser usada
indiretamente fora de seu arquivo de origem por meio de uma interface da
seguinte forma.
Aqui estamos substituindo o código de Arquivo1.cs pelo código abaixo:
namespace AppConsole1; file class Resposta : IResposta{ public string GetFileScopeSecreto() => "Resposta de Arquivo1.cs"; } internal interface IResposta { string GetFileScopeSecreto(); } static class ClasseInternaArquivo1 { internal static IResposta GetString() => new Resposta(); } |
A classe Program vai continuar funcionando da mesma forma.
Agora, se tentarmos acessar diretamente a classe Resposta fora do arquivo onde foi declarada não teremos acesso devido à restrição do escopo de visibilidade estar restrito somente ao arquivo.
Acima ao tentar acessar a classe Resposta no arquivo Program, mesmo definindo o namespace, não teremos acesso.
Alguns fatos sobre o uso do modificador file :
Quais as motivações da implementação deste recurso ?
O uso dos
namespaces continua sendo a maneira preferida de evitar a colisão de nomes de
tipos. No entanto, podemos imaginar vários casos de uso para esse recurso nos
seguintes cenários :
Código gerado: Os templates gerados
normalmente usam o mesmo nome de classe repetidamente, como Item , Info ou
DataSet. Para evitar colisões, temos que aninhar uma classe Item em uma
classe pai ou manter um índice no nome para cada versão gerada, como Item1,
Item2... Assim, o modificador file pode
facilitar significativamente a geração de código.
Métodos de extensão: O uso de métodos de
extensão é hoje em dia uma construção de linguagem popular para desenvolvedores
C#. No entanto, pode haver colisão de nomenclatura do método de extensão. Com
essa restrição de visibilidade de arquivo, agora é fácil ter métodos de extensão
restritos a um único arquivo. Outro problema comum com os métodos de extensão -
resolvido por essa restrição de visibilidade de arquivo - é que eles poluem as
listas suspensas do intellisense.
Classes aninhadas : Para resolver a colisão
de nomes dentro de um projeto, uma solução comum é declarar classes aninhadas privadas. No entanto, este não é um código limpo
porque um nível de recuo extra é adicionado, e, muito recuo atrapalha o código.
Assim, a palavra-chave file pode ajudar a contornar
esse problema.
Módulo e Encapsulamento: Normalmente, o que
você considera como um módulo ou componente não é uma única classe, mas alguns
tipos altamente coesos. Para fins de encapsulamento, um padrão era aninhar
detalhes de implementação privada dentro de classes e tipos aninhados privados.
Esse escopo file torna esse padrão de encapsulamento mais limpo.
Testes : Muitas vezes a estrutura de testes
é padronizada e cada classe de teste tem sua própria classe DataSet, por
exemplo. Aqui também, em vez de declarar classes aninhadas em classes de teste,
a restrição file pode ajudar.
No entanto, lembre-se de que uma classe restrita pelo modificador file
não será visível nos testes. Elas devem ser consideradas como implementação
privada (caixa preta) e devem ser testadas por meio de classes internas ou
públicas que as acessam.
"Eu te
invoquei, ó Deus, pois me queres ouvir; inclina para mim os teus ouvidos, e
escuta as minhas palavras.
Faze maravilhosas as tuas beneficências, ó tu que livras aqueles que em ti
confiam dos que se levantam contra a tua destra."
Salmos 17:6,7
Referências:
NET - Unit of Work - Padrão Unidade de ...