4 pontos por GN⁺ 2025-05-30 | 4 comentários | Compartilhar no WhatsApp
  • A partir do .NET 10 Preview 4, foi adicionada a capacidade de executar um único arquivo C# diretamente com dotnet run app.cs, permitindo rodar código C# mesmo sem arquivo de projeto
  • Graças aos file-based apps, ficou muito mais fácil executar scripts simples, fazer testes e experimentar ideias, como em Python ou JavaScript
  • Referências a pacotes NuGet, definição de SDK e configuração de propriedades de build também podem ser gerenciadas por meio de diretivas dentro do arquivo, aumentando a flexibilidade no desenvolvimento
  • Com suporte a shebang, também pode ser usado em utilitários de CLI, scripts de automação e afins em sistemas Unix
  • Se necessário, é possível converter de forma fluida para um app baseado em projeto, conectando naturalmente aprendizado e prototipagem ao desenvolvimento completo de aplicações

O que é dotnet run app.cs

  • Antes, para executar código C# com a CLI do dotnet, era obrigatória uma estrutura de projeto (.csproj)
  • Agora, é possível executar diretamente com apenas um arquivo .cs, reduzindo bastante a barreira de entrada
  • É adequado para vários usos, como linguagens de script, automação, experimentação e aprendizado
  • Com a integração à CLI, dá para usar imediatamente só com o dotnet, sem instalar ferramentas extras
  • Se o código crescer, ele pode ser expandido para um app baseado em projeto usando a mesma linguagem e as mesmas ferramentas

Suporte a diretivas em nível de arquivo

  • Mesmo em apps baseados em arquivo, as principais configurações de projeto podem ser declaradas diretamente no arquivo .cs por meio de diretivas
  • Referência a pacotes NuGet

    • A diretiva #:package permite referenciar diretamente pacotes NuGet
      • Exemplo:
        #:package Humanizer@2.14.1  
        
        using Humanizer;  
        
        var dotNet9Released = DateTimeOffset.Parse("2024-12-03");  
        var since = DateTimeOffset.Now - dotNet9Released;  
        
        Console.WriteLine($"It has been {since.Humanize()} since .NET 9 was released.");  
        
  • Definição de SDK

    • A diretiva #:sdk permite definir o tipo de SDK
      • Exemplo:
        #:sdk Microsoft.NET.Sdk.Web  
        
      • Também é possível habilitar recursos do ASP.NET Core (Minimal API, MVC etc.)
  • Configuração de propriedades do MSBuild

    • Com #:property, é possível definir diretamente propriedades de build
      • Exemplo:
        #:property LangVersion preview  
        
  • Suporte a shebang para scripts de shell

    • Ao colocar #!/usr/bin/dotnet run no topo do arquivo, ele pode ser usado diretamente como arquivo executável em sistemas Unix
      • Exemplo:
        #!/usr/bin/dotnet run  
        Console.WriteLine("Hello from a C# script!");  
        
      • Após dar permissão de execução, basta executar:
        chmod +x app.cs  
        ./app.cs  
        

Conversão para app baseado em projeto

  • Quando o app crescer ou precisar de mais recursos, é possível converter facilmente para um projeto com o comando dotnet project convert app.cs
  • As diretivas são convertidas automaticamente em propriedades do arquivo .csproj, referências e afins
  • Exemplo de conversão

    • Um arquivo como este:
      #:sdk Microsoft.NET.Sdk.Web  
      #:package Microsoft.AspNetCore.OpenApi@10.*-*  
      
      var builder = WebApplication.CreateBuilder();  
      builder.Services.AddOpenApi();  
      var app = builder.Build();  
      app.MapGet("/", () => "Hello, world!");  
      app.Run();  
      
    • Resultado da conversão:
    <Project Sdk="Microsoft.NET.Sdk.Web">  
      <PropertyGroup>  
        <TargetFramework>net10.0</TargetFramework>  
        <ImplicitUsings>enable</ImplicitUsings>  
        <Nullable>enable</Nullable>  
      </PropertyGroup>  
      <ItemGroup>  
        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.*-*" />  
      </ItemGroup>  
    </Project>  
    

Diferença em relação às abordagens anteriores de script em C#

  • Até agora, era possível executar scripts em C# com ferramentas da comunidade (CS-Script, dotnet-script, Cake etc.), mas isso exigia instalação e configuração de ferramentas separadas
  • Agora, sem instalação extra nem modo especial, é possível executar código imediatamente usando o mesmo compilador e a mesma linguagem C#

Como começar

  • Instale o .NET 10 Preview 4
  • Se usar o Visual Studio Code, é preciso instalar o C# Dev Kit e a versão prerelease mais recente da extensão C# (2.79.8 ou superior)
  • Crie um arquivo .cs e comece a escrever código imediatamente
  • No terminal, execute dotnet run hello.cs
  • Se necessário, converta para projeto com dotnet project convert hello.cs

Saiba mais

Planos futuros

  • Estão previstos suporte a apps baseados em arquivo dentro do VS Code, melhorias no IntelliSense para diretivas, ganho de desempenho e reforço no suporte a depuração
  • Recursos adicionais, como suporte a múltiplos arquivos e melhorias na velocidade de execução, também estão em desenvolvimento
  • dotnet run app.cs torna o C# muito mais acessível, mantendo toda a força do .NET
  • Isso cria uma base para migrar mais rapidamente da prototipagem e educação para o desenvolvimento em produção

4 comentários

 
rkttu 2025-08-18

A DX que oferece a experiência de autocompletar baseada em File-based App já está disponível na versão mais recente da extensão C#, mas originalmente a Microsoft não publicava a extensão em lugares além do VS Code Marketplace.

Para resolver esse incômodo, fiz com que apenas a parte da C# Extension, e não o C# Dev Kit (a parte sob licença MIT), fosse autobuild/autopublish separadamente e a registrei no OpenVSX; com base nisso, compartilho um vídeo simples de demonstração baseado no Kiro.

https://www.youtube.com/watch?v=pIi7CWOPQSA

 
ndrgrd 2025-05-31

Quando usei o recurso C# Interactive antes, não dava para usar pacotes que não estavam instalados localmente, mas parece que isso melhorou agora.

 
GN⁺ 2025-05-30
Comentários do Hacker News
  • Parece ser um recurso que pode ter um grande impacto na produtividade de desenvolvedores .NET, então dá até uma certa frustração pensar por que isso só apareceu agora; e há uma funcionalidade que eu realmente queria em projetos .NET: poder definir comandos customizados por projeto com facilidade, algo no estilo npm run <command>
  • É interessante ver isso sendo promovido ativamente para uso com shebang; essa abordagem parece bem atraente. Go também era muito útil para esse tipo de scripting antes da introdução de módulos, e lembro que o Ubuntu também usava algo parecido, mas os autores de Go eram contra usar Go dessa forma como linguagem de script
    • Na verdade, não é que os autores de Go fossem contra; a explicação é que eles recomendavam usar Go прежде de tudo como linguagem de programação. Já fazia tempo que dava para usar Go facilmente como script com ferramentas como gorun (https://github.com/erning/gorun), e recentemente passaram a permitir executar tudo de uma vez aceitando a tag diretamente, como em go run github.com/kardianos/json/cmd/jsondiff@v1.0.1; é um recurso bem legal
    • Fico curioso sobre de onde veio e desde quando se usa a palavra “shebang”. Na faculdade e no sul dos EUA nos anos 90 e começo dos 2000, normalmente chamávamos de hashbang; só ouvi “shebang” pela primeira vez quando C# ficou popular, embora o termo na verdade já existisse muito antes. Só era uma palavra que eu nunca tinha ouvido ao meu redor
    • Quando eu trabalhava numa empresa .NET, às vezes alguém de repente escrevia scripts de automação em bash. Não havia expertise para manter esses scripts no longo prazo, e a qualidade já era ruim desde o começo. Eu nunca entendia por que simplesmente não faziam a própria ferramenta em C#. Com esse recurso, a abordagem em C# pode começar a parecer uma alternativa muito mais prática
    • Também dá para fazer isso com cargo no Rust, embora ainda não seja suporte oficial https://rust-lang.github.io/rfcs/3424-cargo-script.html
  • O recurso em si é excelente, mas há a desvantagem de um overhead de inicialização de cerca de 0,5 s, mesmo em estado compilado, então ele não serve bem para muitos aplicativos. Ainda assim, existe a limitação do shell scripting dependente de bash, a era do perl já passou, e o Ruby continua sendo excelente para esse tipo de uso, então eu segui usando. Recentemente migrei alguns scripts para Swift, e como ele é basicamente interpretado, acaba sendo muito mais rápido; além disso, executáveis compilados rodam imediatamente, o que é bem impressionante. Eu até criei meu próprio compilador com cache para apps CLI em Swift (https://github.com/jrz/tools). De toda forma, dotnet run já faz cache do resultado da compilação, então não precisa de uma camada extra de cache (para desativar use --no-build, e para ver o caminho do binário use --artifacts-path)
    • Fico curioso de onde vem esse número de 0,5 s; eu testei com hello world e deu 63 ms. No benchmark de biblioteca CLI do neuecc (https://neuecc.medium.com/consoleappframework-v5-zero-overhead-native-aot-compatible-cli-framework-for-c-8f496df8d9d1), nada chega a 0,5 s. E sobre o comentário de que Swift é basicamente interpretado: o JIT do .NET é tiered JIT, então o código não é gerado de uma vez, e sim em várias etapas
    • Ouvi dizer que o dotnet vai introduzir um modo totalmente interpretado na versão 10 ou 11; fico curioso se esse modo também vai se aplicar a esse tipo de uso https://github.com/dotnet/runtime/issues/112748
    • Mesmo que haja um pequeno lag de inicialização após compilar, fico pensando por que Python se tornou tão popular justamente nesse espaço
    • Esse recurso ainda está em estágio inicial de preview; em várias apresentações já disseram que estão cientes dos problemas de velocidade de startup e estão trabalhando em melhorias
    • Se você quer startup rápido, dá para converter facilmente para código nativo seguindo o guia https://learn.microsoft.com/en-us/dotnet/core/deploying/
  • É uma pena que quase não haja menção aos projetos CSX/VBX https://ttu.github.io/dotnet-script/; também é curioso que a decisão pareça incompatível com a forma como dependências de scripts F# são tratadas no runtime do C# https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp-interactive/
    • Sobre a observação de que esforços como CSX/VBX não foram refletidos, vale apontar que oficialmente várias abordagens e ferramentas são mencionadas https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/#existing-ways-to-run-c#-without-projects
    • Pergunta sobre o que exatamente significa dizer que é incompatível com F#; se a questão for diferença de sintaxe, houve uma intenção deliberada de torná-la diferente, e não se quis criar um novo dialeto de script para C#, então recursos como importação de arquivos foram bloqueados de propósito; isso tem a ver com características do próprio C#
  • Existe algo parecido em Kotlin também, https://github.com/Kotlin/kotlin-script-examples/blob/master/jvm/main-kts/MainKts.md (lá o arquivo só funciona se a extensão for obrigatoriamente *.main.kts); esse estilo é ótimo para scripts pequenos e prototipagem, e também é prático para aproveitar recursos da JVM. Ainda assim, para scripts pequenos, Ruby continua sendo o mais confortável, especialmente por causa da sintaxe com crases para executar programas externos
  • Dá para executar scripts C# como scripts bash usando shebang https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/#using-shebang-lines-for-shell-scripts
    • Testei shebang para executar o arquivo diretamente na imagem sdk do .net10 preview 4, mas no começo não funcionou; com dotnet run <file> funcionava. Depois de uma atualização passou a funcionar normalmente, e a causa do problema era que o arquivo usava fim de linha CRLF em vez de LF
    • Fico muito feliz que agora seja possível escrever scripts com type safety; no macOS, por exemplo, é preciso usar #!/usr/local/share/dotnet/dotnet run ou #!/usr/bin/env -S dotnet run no shebang
  • Parece algo capaz de substituir PowerShell; PowerShell às vezes acaba sendo usado quase como uma linguagem exclusiva para o ChatGPT. Em muitas empresas, scripts escritos em PowerShell têm papel central na infraestrutura, mas frequentemente entram num estado praticamente “somente leitura”
    • Parece ter potencial para substituir não só PowerShell, mas uma área muito mais ampla. Se você está numa equipe .NET, talvez nem precise mexer com Python ou shell script: bastaria adicionar um shebang no topo e colar um snippet em C# para resolver quase todo tipo de script. Até serviços de teste talvez nem precisem ser feitos em express.js; um ASP.NET minimal API já resolveria rapidinho
    • Talvez os administradores de sistemas Windows sejam o grupo que mais usa scripts gerados por ChatGPT em grande escala; se eu ainda fosse admin, considerando o nível da documentação oficial da MS, provavelmente eu também teria usado
    • Também dá para chamar código C# a partir do PowerShell https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-type?view=powershell-7.5
    • Na prática, colocar toda a infraestrutura em scripts PowerShell não é nada fácil, e fazer isso só cria um caos enorme. Passando de algumas funções, C# já é muito mais eficiente e a barreira de entrada quase não existe. PowerShell é ideal para scripts ad-hoc pequenos e ocupa o lugar de “linguagem de script padrão do Windows”, como o antigo VBScript
    • Como PowerShell consegue executar código .NET diretamente, isso pode até acabar ampliando a experiência de uso dele
  • Isso parece substituir na prática o NetPad, e se ganhar debugging talvez até empurre o LINQPad para fora do uso principal. Eu também me beneficiei muito do LINQPad no passado, mas a experiência de editor de texto ainda é desconfortável demais para os padrões atuais; ele tem limitações como ferramenta de escrita e edição mais séria de código
    • No meu caso, o uso principal do LINQPad é interação com banco de dados ou exploração de valores com .dump(). Esse dotnet run novo talvez funcione mais como um complemento para isso. Antigamente trabalhei num lugar que odiava PowerShell a ponto de fazer praticamente todo o scripting com LINQPad, e nesse tipo de ambiente ele era útil
    • LINQPad é um produto único no ecossistema .NET, mas o editor de texto em si muitas vezes está entre os piores que já usei. Seria ótimo se fosse trocado por algo como neovim ou monaco. A visualização em tabelas e a rapidez são muito boas, mas comparado a tecnologias de “notebook” como Jupyter Notebook, o leque de uso fica mais estreito; talvez por ser um projeto solo. Mesmo assim, para mexer com dados SQL no trabalho do dia a dia, LINQPad ainda é excelente
    • Não acho que o LINQPad vá ser substituído imediatamente; metade do seu valor está na UI. Fico curioso sobre como será a experiência de usar dotnet run no VSCode ou no Visual Studio, e o quão parecida ela será com a do LINQPad. O ponto forte do LINQPad é a visualização de resultados; se dotnet run só imprimir texto ou exigir muitos plugins extras, a demanda por LINQPad deve continuar. Já para conferir sintaxe e coisas do tipo, dotnet run pode ser a melhor opção; eu mesmo às vezes testo sintaxe no LINQPad
    • A menos que implementem também recursos de GUI e pontos de extensão, vai ser difícil substituir o LINQPad de imediato
  • Estou sinceramente animado com esse recurso; acho que ele pode substituir parte dos scripts PowerShell que uso em pipelines de CI/CD. Eu gosto tanto de PowerShell quanto de Bash, mas certamente há tarefas que ficam muito mais eficientes de resolver mentalmente numa linguagem com sintaxe da família C. Esse recurso pode preencher bem essa lacuna
  • A proposta real (https://github.com/dotnet/sdk/blob/main/documentation/general/dotnet-run-file.md) traz ainda mais informações, especialmente sobre tratamento de múltiplos arquivos e detalhes de implementação, como arquivos de projeto implícitos
 
rkttu 2025-05-30

Também criei 2 exemplos reais relacionados a esse recurso e estou compartilhando na resposta. São códigos de exemplo de aplicativos GUI para Windows e macOS usando servidor MCP e Avalonia. 😊

https://forum.dotnetdev.kr/t/…