Execução de C# Baseada em Arquivo no .NET 10
[[academy-video-youtube({"vid": "2i0MJDHvJq0", "start_time": "0", "title": "File-Based C# Execution in .NET 10", "creator": "Tim Corey", "length": "13m 36s"})]]
C# sempre exigiu um arquivo de projeto para executar o código. Mesmo o simples "Hello World" precisava de um .csproj, um Program.cs, e uma etapa de construção antes de qualquer coisa ser executada. Com o .NET 10, isso muda. Agora você pode escrever um único arquivo .cs e executá-lo diretamente, da mesma forma que você executaria um script Python ou um arquivo Node.js.
Em seu vídeo "Execução de Arquivo C# no .NET 10", Tim Corey passa por todos os aspectos deste recurso: executar um arquivo independente, passar argumentos de linha de comando, adicionar pacotes NuGet no código, publicar em um executável nativo e converter um arquivo em um projeto completo quando o escopo ultrapassa o formato de arquivo único. Se você tem usado aplicativos de console para scripts rápidos e protótipos, isso muda significativamente o fluxo de trabalho.
Executando um Arquivo C# Único
[0:40 - 1:48] Tim começa no VS Code com uma pasta vazia. Sem solução, sem arquivo de projeto, sem código repetitivo. Ele cria um único arquivo chamado demo.cs com uma linha de código:
Console.WriteLine("Hello World");
Console.WriteLine("Hello World");
Para executá-lo:
dotnet run file demo.cs
dotnet run file demo.cs
Esse é o fluxo de trabalho completo. O comando dotnet run file compila e executa o arquivo .cs em um único passo. Não há .csproj intermediário gerado, nem pastas bin ou obj criadas. O modelo mental está mais próximo de script do que de desenvolvimento tradicional em C#: escreva um arquivo, execute-o, veja o resultado.
Tim faz uma comparação direta com Python e JavaScript, onde a execução de arquivo único sempre foi o padrão. .NET 10 traz o C# para esse mesmo território, mantendo a segurança de tipo e desempenho que tornam o C# atraente em primeiro lugar.
Argumentos de Linha de Comando e Usings Implícitos
[1:48 - 3:26] O array args está disponível automaticamente, assim como estaria em um Program.cs padrão com declarações de nível superior. Tim modifica o arquivo para aceitar um argumento de nome:
Console.WriteLine($"Hello {args[0]}");
Console.WriteLine($"Hello {args[0]}");
Executando-o com um argumento:
dotnet run file demo.cs Tim
dotnet run file demo.cs Tim
Isso imprime "Hello Tim". Tim ressalta que Console.WriteLine funciona sem uma declaração using System; porque a execução baseada em arquivo inclui usings implícitos por padrão. Esse é o mesmo comportamento que as declarações de nível superior introduziram no C# 9, agora estendido para arquivos independentes.
O padrão mais amplo que a Microsoft tem seguido é reduzir a cerimônia do C# uma versão de cada vez. Usings globais, declarações de nível superior, e agora arquivos .cs standalone são todos passos para tornar o C# viável para tarefas rápidas que anteriormente requeriam scripts Python ou bash.
Adicionando Entrada do Usuário
[3:26 - 5:43] Tim substitui a abordagem de argumento por entrada interativa para demonstrar que a execução baseada em arquivo suporta toda a gama de padrões de aplicativo de console:
Console.Write("What is your name? ");
string name = Console.ReadLine();
Console.WriteLine($"Hello {name}");
Console.Write("What is your name? ");
string name = Console.ReadLine();
Console.WriteLine($"Hello {name}");
Executar isso solicita uma entrada, lê a resposta e imprime a saudação. A E/S padrão funciona de maneira idêntica a um projeto completo.
Uma limitação que Tim aponta: esse modo é estritamente de arquivo único. Você não pode ter dois arquivos .cs referenciando um ao outro. Se seu código crescer a ponto de você precisar de vários arquivos, é hora de converter para um projeto (abordado mais tarde no vídeo).
Adicionando Pacotes NuGet
[5:43 - 7:49] Aqui é onde a abordagem de arquivo único se torna realmente útil para script. Você pode referenciar pacotes NuGet diretamente dentro do arquivo .cs usando uma diretiva #r no topo:
#r "nuget:Spectre.Console, 0.54.0"
using Spectre.Console;
Console.Write("What is your name? ");
string name = Console.ReadLine();
AnsiConsole.MarkupLine($"Hello [red]{name}[/]");
#r "nuget:Spectre.Console, 0.54.0"
using Spectre.Console;
Console.Write("What is your name? ");
string name = Console.ReadLine();
AnsiConsole.MarkupLine($"Hello [red]{name}[/]");
A sintaxe #r "nuget:..." diz ao runtime para baixar e referenciar o pacote especificado antes da compilação. Tim usa o Spectre.Console para colorir a saída, tornando o texto de saudação vermelho.
Nenhum comando dotnet add package, nenhum .csproj para editar, sem etapa de restauração. A referência do pacote vive no próprio arquivo fonte. Para scripts que precisam de um cliente HTTP, um serializador JSON ou uma biblioteca de formatação, isso elimina a sobrecarga de criar um projeto apenas para adicionar uma dependência.
Publicando para um Executável Nativo
[7:49 - 8:59] Quando você quer distribuir um script baseado em arquivo como um binário autônomo, o comando de publicação lida com isso:
dotnet publish file demo.cs
dotnet publish file demo.cs
Isso produz um executável na pasta artifacts. O binário compilado inclui tudo o que precisa para rodar, sem necessidade do SDK .NET na máquina de destino. Tim observa que compilações baseadas em arquivo usam Native AOT por padrão, o que significa que a saída é um binário único, autônomo, com tempos de inicialização rápidos.
Se o Native AOT causar problemas de compatibilidade com uma biblioteca específica, você pode desativá-lo adicionando uma diretiva de propriedade no topo do arquivo (semelhante ao modo como #r funciona para pacotes). Para a maioria dos casos de uso de script, no entanto, AOT é o padrão certo.
Convertendo para um Projeto Completo
[8:59 - 10:45] A saída de emergência para quando um script se torna grande demais para o formato de arquivo único é o comando de conversão:
dotnet project convert file demo.cs
dotnet project convert file demo.cs
Isso gera um arquivo .csproj que inclui as referências de pacotes NuGet das diretivas #r e move o código para uma estrutura de projeto padrão. A partir desse ponto, você pode adicionar vários arquivos, configurar as configurações de compilação e usar todo o sistema de projeto .NET.
Tim considera isso uma progressão natural: começar com um único arquivo para experimentos rápidos e, quando o escopo se expandir, promovê-lo a um projeto sem reescrever nada. As diretivas #r se traduzem de maneira clara em entradas <PackageReference> no .csproj gerado.
Native AOT e Notas de Plataforma
[10:45 - 12:42] Por padrão, a execução baseada em arquivo compila com Native AOT, produzindo os tempos de inicialização mais rápidos possíveis. Tim observa que isso é ideal para ferramentas CLI e scripts onde o desempenho de inicialização a frio importa. Se uma biblioteca não for compatível com AOT, o recurso pode ser desativado com uma propriedade de nível de arquivo.
No Linux e macOS, você também pode adicionar um hashbang (#!/usr/bin/dotnet run file) no topo do arquivo .cs, tornando-o diretamente executável a partir do shell sem digitar o prefixo dotnet run file. Isso traz o C# totalmente para o território de script junto com bash, Python e Ruby.
Encerrando: C# como uma Linguagem de Script
[12:42 - 13:05] O recurso que Tim destaca como mais impactante é a eliminação da sobrecarga de projetos para pequenas tarefas. Os aplicativos de console sempre foram a escolha para experimentos rápidos, scripts de automação e ferramentas pontuais. A execução baseada em arquivo remove a cerimônia que os tornava mais pesados do que precisavam ser, mantendo todas as vantagens (segurança de tipo, desempenho, ecossistema NuGet) que faz o C# valer a pena em comparação a uma linguagem de script.
Conclusão
[13:05 - 13:36] Resumindo: a execução baseada em arquivos do .NET 10 permite que você execute um único arquivo .cs com dotnet run file, referencie pacotes NuGet com diretivas #r, publique em um binário nativo com dotnet publish file, e converta para um projeto completo com dotnet project convert file quando você ultrapassar o formato de arquivo único. Native AOT está ativado por padrão, e usuários de Linux/macOS obtêm suporte a hashbang para execução em nível de shell.
Para qualquer coisa que você use atualmente um aplicativo de console para prototipar ou automatizar, vale a pena tentar isso como uma alternativa mais leve.
Dica de Exemplo: Se você se pegar criando aplicativos de console apenas para testar um pacote NuGet ou depurar uma chamada de API, experimente a execução baseada em arquivo. Crie um arquivo .cs, adicione #r "nuget:PackageName, Version" no topo, escreva seu código de teste e execute-o com dotnet run file. Quando terminar, exclua o arquivo. Nenhuma limpeza de projeto necessária.
Assista ao vídeo completo aqui no canal do YouTube dele IAmTimCorey e obtenha mais insights sobre fluxos de trabalho modernos de desenvolvimento em C#.
