No primeiro dia dos 30 dias de .NET eu fui entender o que acontece por trás de um simples dotnet run.
Mas antes do dotnet run existe o projeto em si.
Quando criamos uma aplicação .NET, mesmo a mais simples possível, alguns arquivos e pastas já aparecem automaticamente. Program.cs, .csproj, obj, depois bin e a gente simplesmente segue programando sem se preocupar em entender.
Eu mesma já abri um .csproj várias vezes para instalar um pacote, mudar alguma configuração ou conferir a versão do .NET e depois fechei sem entender direito o que tinha feito.
Então hoje resolvi abrir essa caixinha e entender para que serve cada uma dessas coisas.
Criando o projeto mais simples possível
Vamos começar criando uma aplicação Console:
O dotnet new cria projetos e outros arquivos a partir de templates. Nesse caso estamos usando o template console e dando ao projeto o nome Dia02.
Entrando na pasta temos uma estrutura parecida com essa:
Pouca coisa pra começar, mas já temos bastante coisa para entender aqui.
Program.cs — onde tudo começa
Abrindo o Program.cs de uma aplicação Console moderna encontramos algo parecido com:
Console.WriteLine("Hello, World!");
O Program.cs é o arquivo onde encontramos o ponto de entrada da aplicação. É onde a execução do nosso programa começa e, em aplicações maiores, normalmente é onde configuramos e inicializamos os componentes necessários antes da aplicação começar a trabalhar de fato.
Se você já viu projetos C# mais antigos, talvez esteja sentindo falta de algumas coisas no Program.cs
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
Desde o C# 9 temos os Top-level statements, que permitem escrever o código do ponto de entrada da aplicação sem declarar explicitamente uma classe Program e um método Main, como no segundo exemplo. O compilador gera o ponto de entrada necessário para nós, deixando o Program.cs bem menos verboso e mais bonito.
.csproj — o arquivo que descreve nosso projeto
Agora chegamos no arquivo mais importante do artigo.
Se abrirmos o Dia02.csproj, vamos encontrar algo parecido com:
É no .csproj que ficam várias informações que dizem ao sistema de build como aquele projeto deve ser tratado: qual SDK utilizar, qual framework ele tem como alvo, referências a pacotes, referências a outros projetos e diversas configurações de compilação. Aah, e é um arquivo XML.
Olhando para o nosso exemplo:
<Project Sdk="Microsoft.NET.Sdk"> : define o Project SDK utilizado pelo projeto. Nesse caso estamos usando o SDK base do .NET. Em uma aplicação ASP.NET Core, por exemplo, é comum encontrarmos Microsoft.NET.Sdk.Web.
<PropertyGroup> : agrupa propriedades e configurações do projeto. Ele não define uma configuração específica sozinho, mas funciona como um "grupo" para as propriedades que estão dentro dele.
<OutputType>Exe</OutputType> : define o tipo de saída que será gerada pelo projeto. Exe indica que estamos construindo uma aplicação executável.
<TargetFramework>net10.0</TargetFramework> : define para qual Target Framework o projeto será construído. No exemplo, nosso alvo é o .NET 10. Isso não quer dizer "qual SDK tenho instalado", mas sim qual framework essa aplicação tem como alvo.
<ImplicitUsings>enable</ImplicitUsings> : faz com que o SDK adicione automaticamente alguns using comuns ao projeto. É por isso que conseguimos usar coisas como Console.WriteLine() sem necessariamente escrever using System; no começo do arquivo.
<Nullable>enable</Nullable> : habilita o contexto de Nullable Reference Types, permitindo que o compilador nos avise sobre situações em que uma referência pode ser null. Por exemplo, ele passa a diferenciar string nome de string? nome.
E quando instalamos um pacote NuGet?
Agora vamos mexer um pouquinho no nosso projeto.
Podemos adicionar um pacote usando a CLI:
dotnet package add Dapper
Depois disso, se abrirmos novamente nosso .csproj, alguma coisa nova apareceu:
Vamos entender o que apareceu de novo:
<ItemGroup> : enquanto o PropertyGroup agrupa propriedades e configurações, o ItemGroup agrupa itens que fazem parte ou são utilizados pelo projeto, como pacotes, referências a outros projetos e arquivos.
<PackageReference Include="Dapper" Version="..." /> : declara uma dependência de um pacote NuGet. O Include="Dapper" informa qual pacote queremos utilizar e o Version="..." informa qual versão desse pacote o projeto utiliza.
Ao instalar um pacote NuGet, a dependência fica registrada no próprio .csproj, junto com a versão que o projeto utiliza. É também por isso que não precisamos enviar os pacotes junto com nosso código para o Git. Quando outra pessoa clona o projeto, o .NET consegue ler os PackageReference e restaurar as dependências necessárias.
E de onde surgiram bin e obj?
Quando executamos o dotnet build
o .NET inicia o processo de build do nosso projeto e, no meio disso, duas pastas que provavelmente todo desenvolvedor .NET já encontrou são atualizadas ou aparecem: bin e obj.
Apesar de as duas estarem relacionadas ao processo de build, elas têm funções diferentes.
A pasta bin é onde ficam os principais arquivos resultantes da compilação da nossa aplicação. Dentro dela, o .NET organiza esses arquivos de acordo com a configuração utilizada no build e o Target Framework do projeto.
Já a pasta obj funciona como uma área de trabalho do processo de build. Enquanto o resultado que nos interessa vai para bin, durante a compilação o .NET e o MSBuild precisam gerar e armazenar diversos arquivos intermediários. É na obj que essas informações ficam.
Normalmente, nenhuma das duas é versionada no Git. Se apagarmos bin e obj e executarmos novamente o dotnet build, o .NET gera de novo o que for necessário.
Concluindo
Na correria das entregas é muito fácil simplesmente criar o projeto, instalar os pacotes, rodar um dotnet build e seguir a vida sem pensar muito no que está acontecendo por trás de tudo isso. E, na maior parte do tempo, vai funcionar mesmo. Mas entender como o projeto está estruturado e de onde o .NET tira as informações que precisa para construir nossa aplicação faz bastante diferença quando alguma coisa deixa de funcionar como esperado quase o tempo todo. Quanto mais entendemos as ferramentas que usamos todos os dias, mais fácil fica investigar um erro e, por consequência, mais fácil e rápido fica entregar a task.
Até amanhã!
Referências
- .NET Project SDK overview — Microsoft Learn
- MSBuild properties for Microsoft.NET.Sdk — Microsoft Learn
- Target frameworks in SDK-style projects — Microsoft Learn
- Top-level statements — Microsoft Learn
- Package references in project files — Microsoft Learn
- Common MSBuild project items — Microsoft Learn






Top comments (0)