.NET

O que é o ASP.NET Core?

O ASP.NET Core é uma versão do ASP.NET para a plataforma .NET Core. Só que antes de conhecê-lo precisamos voltar um pouco no tempo.

Em 2002, no lançamento da versão 1.0 do .NET Framework, a Microsoft lançou com esta plataforma o ASP.NET, como um sucessor da tecnologia ASP ( Active Server Pages).

Por se tratar de uma extensão do .NET Framework, assim como ele, no início o ASP.NET possuía poucos recursos. Suportava todas as linguagens de programação compatíveis com a plataforma .NET, mas ainda era muito limitado.

C# (C Sharp) Intermediário
Curso de C# (C Sharp) Intermediário
CONHEÇA O CURSO

Replicando o desenvolvimento Desktop na web

No seu lançamento, o ASP.NET trouxe o modelo de aplicação Web Forms (ASP.NET Web Forms), cujo objetivo era replicar o desenvolvimento Desktop em uma aplicação web.

Em 2002, o desenvolvimento Desktop possuía ferramentas como Delphi e Visual Basic, que permitiam que uma tela fosse criada com o arrastar de controles. Desta forma, o desenvolvedor não precisava se preocupar com a codificação dos componentes da interface, apenas com a lógica de negócios.

Replicando isso na web, o ASP.NET Web Forms permitia que os desenvolvedores criassem interfaces web arrastando componentes. O ASP.NET se encarregaria de criar o HTML, CSS e JavaScript da página, e o desenvolvedor poderia focar na lógica de negócio da aplicação.

Olhando em retrospecto, na época esta foi uma boa solução, pois ajudou os desenvolvedores Desktop migrarem para o desenvolvimento web. Entretanto, o HTML gerado pelo ASP.NET tinha pouca legibilidade, hoje seria considerado um código muito poluído, por isso ao logo do tempo o Web Forms entrou em desuso e hoje está descontinuado.

Padrões de projetos vem ao resgate

Para melhorar a qualidade das aplicações ASP.NET, em 2009 foi lançado o modelo de aplicação MVC (ASP.NET MVC), cujo objetivo era aplicar o padrão de projetos MVC. Neste tipo de aplicação, os componentes são separados em três camadas lógicas:

  • Model (camada de negócio);
  • View (camada de apresentação);
  • Controller (camada de controle).

Um model representa o estado de um aspeto particular da aplicação. O controller lida com as interações e alterações do model para refletir o estado da aplicação e passa essas informações para a view. A view recebe as informações do controller e as exibe para o usuário.

Não possuindo mais o recurso de arrastar componentes para criar as páginas, mas isoladas na camada view, o ASP.NET MVC permitia que um desenvolvedor front-end pudesse focar na criação das páginas, enquanto outro lidasse com a lógica de negócio das camadas model e controller.

A constante busca pela evolução

Buscando uma evolução constante, ao longo do tempo foram lançados vários recursos ao ASP.NET, como: Web API, que permite criar APIs; Razor, uma template engine; ASP.NET AJAX, que facilita a adição de Ajax em aplicações ASP.NET; entre outros.

Nesta procura por evolução, a Microsoft notou que a comunidade poderia ajudá-la, assim, em 2012 decidiu abrir o código fonte do ASP.NET (entre outros produtos). E trabalhando em conjunto com a comunidade nas atualizações do ASP.NET, notou que a plataforma necessitava de muitas modificações que não poderiam ser aplicadas na versão existente, assim nasceu o ASP.NET Core.

C# (C Sharp) - ASP.NET MVC
Curso de C# (C Sharp) - ASP.NET MVC
CONHEÇA O CURSO

Então surge o ASP.NET Core

Sucessor do ASP.NET, o ASP.NET Core é um framework open-source, multiplataforma, criado pela Microsoft e a comunidade. Leve, rápido e modular, funciona em conjunto com o .NET Core.

Lançado em 2016, mesmo sendo um sucessor do ASP.NET, o ASP.NET Core foi criado totalmente do zero, para que não precisasse se preocupar com código legado permitindo assim seguir o padrão de desenvolvimento web moderno.

Assim como outras plataformas, o ASP.NET Core é totalmente modular, recursos podem ser adicionados via pacotes Nuget. O que permitiu que a plataforma fosse mais performática que seu antecessor. Além disso, não necessita de uma IDE específica, todo desenvolvimento pode ser feito via linha de comando. O que permite que uma aplicação criada em uma plataforma possa ser movida para outra, sem a perda de nenhum recurso ou funcionalidade.

Devido a todo seu poder, caso necessite criar uma aplicação web, não deixe de dar uma olhada no ASP.NET Core.

O que é o NuGet?

O NuGet é um gerenciador de dependências para a plataforma .NET. Ele define como os pacotes desta plataforma são criados, publicados e consumidos. Fornecendo ferramentas para cada uma dessas funções.

C# (C Sharp) Intermediário
Curso de C# (C Sharp) Intermediário
CONHEÇA O CURSO

Estrutura de um pacote NuGet

Caso não esteja familiarizado com desenvolvimento .NET, antes de falar da estrutura de um pacote NuGet, é importante compreender que nesta plataforma podemos criar projetos de biblioteca, ou apenas biblioteca. Este tipo de projeto não pode ser executado diretamente, ele não é um executável. Trata-se de códigos úteis para outros projetos.

Ao ser compilada, uma biblioteca gera um arquivo DLL. Será esta DLL que os outros projetos irão utilizar. O NuGet aproveita desta característica da plataforma para definir seus pacotes.

Na prática, um pacote NuGet é um arquivo compactado com a extensão .nupkg que contém um código compilado (DLL), outros arquivos relacionados a este código (como imagens, etc.) e um arquivo de configuração que contém informações sobre o pacote, como: número de versão, criador, etc.

Estes pacotes .nupkg podem ser publicados em repositórios públicos ou privados, onde os desenvolvedores podem consumi-los, adicionando-os em seus projetos e utilizando no código as funcionalidades que fornecerem.

Distribuição dos pacotes

Para facilitar a distribuição dos pacotes, o NuGet mantém um repositório público, o NuGet.org, onde qualquer desenvolvedor pode publicar, pesquisar e consumir pacotes. Contendo mais de 100.000 pacotes, este repositório é utilizado por milhões de desenvolvedores .NET/.NET Core todos os dias.

Entretanto, o NuGet também permite a criação de repositórios privados ou locais. Assim, um desenvolvedor não precisa publicar em um repositório público um pacote crítico que é utilizado apenas pelos projetos da sua empresa.

Independente do tipo do repositório, ele funciona como a ligação dentre os criadores dos pacotes e os desenvolvedores que os consome. Podemos ilustrar isso com a imagem abaixo:

Os criadores publicam os arquivos .nupkg nos repositórios, onde os desenvolvedores podem pesquisá-los e adicioná-los nos projetos .Net.

Gerenciamento dos pacotes

Da mesma forma que outras plataformas, o .NET está disponível em várias versões, consequentemente, o desenvolvedor que estiver criando um pacote precisa definir para qual versão da plataforma ele será compatível. Um mesmo pacote pode ser compatível com uma versão específica ou várias.

Ao ser consumido, o NuGet irá analisar se o pacote é compatível com a versão do .NET definida no projeto destino. Caso não seja, ele não será adicionado ao projeto. Isso também vale para as dependências deste pacote.

Assim como qualquer projeto, um pacote pode fazer uso de outros pacotes. Mas o desenvolvedor não precisa se preocupar com isso, pois o NuGet irá cuidar de qualquer dependência de nível inferior que houver.

Para compreender melhor este ponto, a imagem abaixo ilustra bem como funciona esta “árvore” de dependência (o NuGet também dá o nome de “grafo de dependência”):

Observe que na imagem alguns pacotes se repetem. Quando isso ocorrer, o pacote em questão não será obtido várias vezes. Mesmo que sejam versões diferentes, o NuGet irá verificar qual versão do pacote pode ser compartilhada entre todos que o referenciam e irá obter apenas esta versão.

Ferramentas e outras características do NuGet

Este gerenciador de pacotes fornece uma ferramenta de linha de comando que permite criar, pesquisar e instalar pacotes. O NuGet CLI pode ser obtido no NuGet.org, entretanto, como o SDK do .NET Core e o Visual Studio (tanto a versão para Windows, quanto a de MacOS) já fornecem suporte a este gerenciador, ele raramente é utilizado.

Outro motivo do pouco uso desta ferramenta de linha de comando é a falta de suporte a projetos do Visual Studio.

Todo projeto .NET possui um arquivo onde serão salvas suas configurações. Por exemplo, um projeto de console simples, definirá um arquivo similar ao abaixo:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

</Project>

Comumente conhecido como “arquivo de projeto”, ele também é utilizado pelo NuGet registrar os pacotes que estiverem sendo utilizados. Porém, caso um pacote seja instalado com o NuGet CLI, ele não é registrado neste arquivo.

Quando registrado, o pacote é indicado em uma tag <PackageReference> que contém o nome e a versão utilizada:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
  </ItemGroup>

</Project>

Assim, caso seja utilizada apenas o NuGet CLI, é necessário que esta tag <PackageReference> seja adicionada manualmente e a ferramenta é utilizada para restaurar os pacotes do projeto.

Por serem utilizados em tempo de compilação e execução, não é necessário que os binários dos pacotes sejam compartilhados junto com o código do projeto. Mas antes de ser compilado na máquina destino, os pacotes precisam ser restaurados.

Utilizando o NuGet CLI, isso é feito com o comando nuget install. Já o SDK do .NET e o Visual Studio realiza este procedimento automaticamente quando o projeto for compilado ou executado.

C# (C Sharp) - APIs REST com ASP.NET Web API
Curso de C# (C Sharp) - APIs REST com ASP.NET Web API
CONHEÇA O CURSO

Conclusão

Esta foi uma breve introdução do NuGet. Por ser uma ferramenta integrada a plataforma .NET, muitos não dão o devido valor que este gerenciador de pacotes merece.

Mas como vimos aqui, o trabalho de um gerenciador de pacotes é muito importante e, ao menos o NuGet, não se resume apenas em baixar os arquivos dos pacotes. Para que seja eficiente são realizadas muitas tarefas nos bastidores.

Caso queria conhecer mais sobre esta ferramenta, já abordei a criação de repositórios para ela.

O funcionamento do garbage collector no .NET

A CLR – o ambiente de execução do .NET Framework – é um ambiente gerenciado e, por isso, não precisamos nos preocupar diretamente com questões relacionadas a liberação de memória. Isso é possível por causa de um componente importantíssimo da CLR: trata-se do garbage collector. O garbage collector tem exatamente a responsabilidade de lidar com a liberação da memória associada a uma variável e/ou objeto quando este não é mais utilizado em nenhum ponto do nosso código.

Entender como o garbage collector funciona no .NET é essencial para que possamos entender como um todo como a CLR funciona. Questões relacionadas ao garbage collector também são muito úteis quando precisamos escrever código de alta performance para aplicações que exigem respostas próximas ao real-time “de verdade”. Por isso, vamos entender como o garbage collector funciona na CLR.

Como funciona o gerenciamento de memória no .NET?

No artigo C# Gerenciamento de memória no C#: stack, heap, value-types e reference-types que escrevi aqui para o blog da TreinaWeb, apresentei as duas principais divisões da área de memória durante a execução de uma aplicação .NET: a stack, para os value-types; e a heap, para os reference-types. Dependendo do tipo de “dado” que você aloca em uma variável, o dado pode ser deslocado ou para a stack – se estivermos falando de structs – ou para a heap – se estivermos falando de tipos ditos “complexos”, como objetos.

Desenvolvedor C# Sênior
Formação: Desenvolvedor C# Sênior
A formação Desenvolvedor C# nível Sênior da TreinaWeb tem como objetivo apresentar conceitos avançados do C#, como covariância, contravariância e invariância de interfaces; utilização extensiva de delegates, expressões lambda e métodos de extensão. Por fim, o LINQ e o Entity Framework, ferramentas importantíssimas e essenciais no .NET, são abordadas e estudadas.
CONHEÇA A FORMAÇÃO

Quando falamos sobre o garbage collector, é importante frisar que este atua organizando a memória na heap, embora ele utilize as referências guardadas na stack para determinar o que ainda está em uso ou não. Os objetos que são alocados na heap acabam sendo divididos em três grupos, também chamados de gerações:

  • geração 0: é a primeira geração onde um objeto é alocado. Assim que algo é alocado na heap,o objeto alocado é colocado imediatamente como sendo parte da geração 0;
  • geração 1: trata-se de uma geração de transição, onde objetos que são utilizados de maneira “média” são alocados;
  • geração 2: é uma geração que contém objetos que são utilizados por mais tempo e que, por isso, precisam existir na memória por um tempo maior.

O que o garbage collector faz basicamente é migrar os objetos entre estas três áreas distintas e eliminar as áreas de memória associadas a objetos que não são mais utilizados.

O ciclo de trabalho do garbage collector na heap

O garbage collector trabalha em ciclos de análise sobre as gerações que existem na heap. O que diferencia o funcionamento do garbage collector sobre as gerações é a peridiocidade da inspeção: a geração 0, por ser menor na maioria das vezes, sofre análises do garbage collector mais frequentes do que as gerações 1 e 2 por exemplo. Nestas análises, o que o garbage collector faz é verificar se os integrantes das gerações estão ainda sendo utilizados e, caso algum integrante não seja mais necessário, este é removido, fazendo com que a área de memória correspondente seja liberada e fique disponível para novas alocações.

É importante notar também que os ciclos de análise ocorrem na geração que é alvo do ciclo e nas gerações anteriores. Por exemplo: se o garbage collector precisa analisar a geração 0, somente ela é analisada. Se o garbage collector precisa analisar a geração 1, as gerações 1 e 0 são analisadas. Se o garbage collector precisa analisar a geração 2, as gerações 2, 1 e 0 são analisadas. Em decorrência desse funcionamento, o ciclo de análise na geração 2 ganha o nome de coleta completa, pois todas as gerações acabam sendo analisadas.

Essa análise do garbage collector pode ocorrer em situações pré-definidas:

  • Quando o sistema operacional informa que possui pouca memória física disponível;
  • O tamanho das gerações é estourado;
  • O método GC.Collect() é invocado, o que caracteriza uma chamada explícita para o processo de análise do garbage collector dentro da aplicação.

Promoções de geração em objetos

Os objetos são inicialmente alocados na geração 0 – portanto, na geração que sofre coletas mais rápidas – porque a CLR supõe que estes objetos não serão mais necessários muito rapidamente, o que faria com que estes objetos fossem removidos rapidamente da memória. E isso é verdade para a maioria dos cenários. Porém, alguns objetos podem precisar sobreviver por mais de um ciclo de análise do garbage collector… Quando o garbage collector detecta um objeto que precisa sobreviver por mais tempo na memória do que o esperado para a geração onde ele se encontra, o objeto sofre o que é chamado de promoção: o objeto é deslocado para a geração superior, sofrendo ciclos mais espaçados de análise do garbage collector. Por exemplo: se um objeto que está na geração 0 sobrevive a um ciclo de análise, o mesmo é deslocado para a geração 1. Se um objeto sobrevive a um ciclo de análise sob a geração 1, o mesmo é deslocado para a geração 2, sofrendo a análise do garbage collector de maneira mais espaçada ainda.

Esse processo de promoção pode tornar a gerência de memória um processo muito lento, já que esse deslocamento de gerações pode exigir uma quantidade de processamento computacional considerável, dependendo da quantidade de objetos alocados… Por isso, o CLR sempre está “supervisionando” o trabalho do garbage collector. Se o garbage collector passa a detectar que a taxa de sobrevivência de objetos em uma determinada geração é muito alta, a CLR aumenta o tamanho da geração em questão, evitando que as gerações tenham seu tamanho estourado frequentemente. A CLR sempre tenta equilibrar os ciclos de análise do garbage collector e o tamanho das gerações – as gerações também não podem ser sempre expandidas, pois isso deixaria o sistema operacional sem memória em um curto espaço de tempo.

Áreas efêmeras

O CLR e o garbage collector supõe que os objetos que fazem parte das gerações 0 e 1 terão um ciclo de vida muito curto, sendo eliminados rapidamente da memória. Por isso, estas gerações também são chamadas de gerações efêmeras.

As gerações também costumam ser agrupadas em segmentos de memória, segmentos estes que são gerenciados pelo garbage collector. Segmentos que possuem as gerações 0 e 1 também são chamados de segmentos efêmeros.

O garbage collector também realiza a manipulação destes segmentos. Os segmentos recém-criados também são definidos como segmentos efêmeros. Quando o garbage collector cria mais um novo segmento, o segmento que antes era efêmero deixa de ter essa característica, passando a ser considerado um segmento de geração 2 (a geração com objetos que sobrevivem por mais tempo). O novo segmento passa a ser considerado neste momento como o segmento efêmero.

No próximo artigo, iremos analisar em detalhes como o garbage collector realiza o trabalho de remoção e promoção de objetos entre os segmentos gerenciados pelo garbage collector.

Afinal: o que é de fato o LINQ?

Certamente, uma das features mais interessantes e legais que o .NET e seu ecossistema oferece é o LINQ. LINQ é um acrônimo para Language Integrated Query, ou Consulta Integrada à Linguagem . Trata-se de um “framework” dentro do .NET destinado a auxiliar os desenvolvedores a escrever expressões de consulta diretamente em C# de maneira agnóstica.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Mas o que exatamente é o LINQ?

Para entender melhor: pense nas seguintes hipóteses dentro de um software:

  • Se o software em questão precisar realizar consultas em um banco de dados relacional, provavelmente será necessário escrever consultas SQL;
  • Se o software em questão precisar realizar consultas em um arquivo XML, provavelmente será necessário utilizar expressões XPath e/ou XQuery;
  • Se o software em questão precisar realizar consultas em coleções de objetos, provavelmente será necessário utilizar blocos de código com a linguagem na qual o software está sendo desenvolvido.

Essa complexidade é adicionada pelo fato de estarmos tratando de fontes de dados heterogêneas de dados, cada qual com suas linguagens de manipulação específicas. Ou seja: se seu software se conecta a uma base de dados relacional e manipula objetos, você provavelmente precisará desenvolver e dar manutenção em pelo menos três linguagens diferentes: SQL, XPath (ou XQuery) e a linguagem utilizada para desenvolver a aplicação em si.
O LINQ tem como objetivo justamente remover essa complexidade, pois ele abstrai a complexidade envolvida na utilização de diferentes linguagens de consulta, como SQL, xPath e xQuery. Essa abstração é feita em cima de uma API de alto nível compatível com as linguagens integrantes do .NET Framework. Ou seja: você consegue consultar uma base de dados relacional, um arquivo XML uma coleção de objetos através de uma API unificada, invocada através de uma linguagem integrante do .NET Framework. Trazendo para um exemplo mais palpável: você consegue unicamente com código C# fazer consultas a conjuntos de objetos, bases de dados relacionais e arquivos XML, sendo o LINQ o encarregado de fazer a devida “tradução” para cada uma das fontes a serem consultadas.

Providers LINQ e árvores de expressão (expression trees)

O LINQ consegue trabalhar de maneira agnóstica (ou seja, a mesma API do LINQ consegue trabalhar em cima de várias fontes de dados diferentes) principalmente por causa de dois pilares: os providers e as árvores de expressão – ou expression trees. Para entendermos cada um deles, vamos a partir deste ponto adotar o C# como a linguagem de referência.

C# (C Sharp) Intermediário
Curso de C# (C Sharp) Intermediário
CONHEÇA O CURSO

De maneira geral e simplificada, uma expression tree é um trecho de código organizado como uma árvore onde cada nó pode corresponder a um valor, uma chamada de método ou até mesmo um operador aritmético ou lógico. No .NET, as árvores de expressão são definidas pela classe Expression, advinda do namespace System.Linq.Expressions.
Vamos montar uma árvore de expressão simples: uma árvore que retorna true caso receba um número menor que 5 ou retorna false no caso contrário. Para isso, precisamos criar um delegate que seja capaz de realizar essa análise… No .NET, existem dois tipos de delegate especializados e já disponibilizados pela API do LINQ:

  • Func: é um delegate que indica que um valor vai ser retornado. Delegates do tipo Func podem não receber parâmetros, mas sempre tem que prover algum retorno;
  • Action: é um delegate que indica que nenhum valor será retornado. Delegates do tipo Action podem não receber parâmetros e nunca irão retornar um valor.

Se verificarmos a situação acima, veremos que um delegate do tipo Func com um parâmetro de entrada do tipo int e uma saída do tipo boolean é o mais adequado. Sendo assim, utilizando expressões-lambda, podemos escrever esta definição:

Func<int, bool> expr = num => num < 5;

Para que este delegate se torne uma árvore de expressão de verdade, é necessário que ele seja envolvido pela classe Expression:

Expression<Func<int, bool>> expr = num => num < 5;

Agora, temos uma árvore de expressão completa com três ramificações:

  • O argumento do tipo int de entrada;
  • O operador de comparação &gt;, revelando que se trata de uma árvore de expressão binária;
  • O 5, um valor constante que deve ser utilizado para comparação.

Qualquer expressão LINQ é decomposta nestas árvores de expressão. Neste momento, entra em cena os providers LINQ.
Os providers LINQ são utilizados basicamente para fazer a tradução das árvores de expressão para cada uma das fontes de dados na qual a expressão LINQ está conectada. Os principais providers LINQ são:

  • LINQ to objects: utilizado quando a fonte de consulta é um conjunto de objetos;
  • LINQ to XML: utilizado quando a fonte de consulta é um XML;
  • LINQ to SQL: utilizado quando a fonte de consulta é um banco de dados relacional.

As principais estruturas dos providers LINQ são as interfaces IQueryProvidere IQueryable. Todos os providers LINQ e suas variações são obrigados a implementar estas interfaces.
Através das implementações dos providers LINQ, as expressões de consulta podem ser traduzidas para as suas respectivas fontes de dados… Por exemplo: vamos considerar a árvore de expressão anterior (Expression expr = num =&gt; num &lt; 5) com o número 4 como entrada.

Se estivéssemos falando de LINQ to Objects, cada nó que faz parte da expressão seria traduzido para o código C# correspondente. Teríamos o resultado abaixo:

Se estivéssemos falando de LINQ to SQL, cada nó que faz parte da mesma expressão seria traduzido para o código SQL correspondente. Teríamos o resultado abaixo:

Já se estivéssemos falando de LINQ to XML, cada nó que faz parte da mesma expressão seria traduzido para o código xPath/xQuery correspondente. Teríamos o resultado abaixo:

Veja que o LINQ, de acordo com a fonte de dados que está sendo analisada, utiliza o provider para realizar uma "tradução" da API de alto nível em C# para o código correspondente ao tipo da fonte de dados que está sendo utilizada. E esse processo torna a API completamente independente da fonte de dados a qual esta se conecta: quem fica responsável por dizer ao LINQ como cada nó da árvore de expressão tem que ser traduzido é o provider.

C# (C Sharp) Avançado
Curso de C# (C Sharp) Avançado
CONHEÇA O CURSO

Existem muito mais coisas do LINQ a serem exploradas!

O LINQ é de fato uma ferramenta muito poderosa quando utilizada corretamente (especialmente quando estamos falando do LINQ to SQL). Este primeiro post na verdade tem a intenção de mostrar os princípios básicos e o funcionamento interno do LINQ. Nos próximos posts, iremos começar a analisar alguns pontos interessantes para quem utiliza o LINQ no dia-a-dia.

O que é e como começar com C# (C Sharp)?

Atualmente são tantas as opções de linguagens de programação à nossa disposição que ficamos perdidos em qual estudar. Para lhe ajudar nessa escolha, vamos apresentar a linguagem C#.

O C# é uma linguagem de programação muito popular, sendo uma excelente escolha devido a sua baixa curva de aprendizado e simplicidade (mas sem deixar de ser uma linguagem poderosa). Além disso, ela é a linguagem principal do .NET Framework, o framework para desenvolvimento da Microsoft.

Se você não tem nenhum conhecimento sobre programação, não tem problema: o C# é ótimo para você começar seus estudos, pois aprendê-lo é muito mais fácil do que parece. Caso você já tenha uma bagagem em alguma linguagem (como por exemplo Java ou C++), você não encontrará problemas em se ambientar com ele.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

O que é C#?

O C# é uma linguagem de programação multiparadigma criada pela Microsoft, sendo a principal da plataforma .NET. Por ser uma linguagem que suporta, entre outros paradigmas, a orientação à objetos, ela suporta conceitos comuns como encapsulamento, herança e polimorfismo. Trata-se também de uma linguagem fortemente tipada e case-sensitive, ou seja, faz diferenciação entre letras minúsculas e maiúsculas.

O C# veio para facilitar o processo de desenvolvimento, tendo inúmeros recursos que proporcionam uma grande produtividade para os desenvolvedores que a utilizam.

O que pode ser feito?

O C# é uma linguagem multiplataforma. Sendo assim, você pode utilizá-la para desenvolver para plataformas web, dispositivos móveis e aplicações desktop. Com a praticidade dessa linguagem, você pode, de forma relativamente fácil, desenvolver desde projetos mais simples até projetos complexos e multiplataforma.

Sintaxe do C#(C Sharp)

A sintaxe do C# é simples. Veja o tradicional “Hello World”:

public class Exemplo
{
    public static void Main()
      {
        System.Console.WriteLine("Hello World!");
      }
 }

Utilizar estruturas de tomada de decisão com C# é muito fácil. Veja o tradicional “if/else”.

int idade = 18;
if ( idade >= 18 )
{
    Console.WriteLine( "Você é maior de idade“ );
}
else
{
    Console.WriteLine( "Você é menor de idade" );
}

Você também pode utilizar estruturas de repetição, como a estrutura “for”, sem problemas… Veja o código abaixo, onde fazemos uma verificação e imprimimos somente os números que forem menores ou iguais a 5:

class Exemplo
{
    static void Main() 
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine(i);
        }
    }
}

Mercado de trabalho

Você pode escolher uma linguagem de programação que mais te agrade, mas também é importante observar como anda o mercado de trabalho. O C# é uma das linguagens mais utilizadas no mundo e o mercado está em alta para essa linguagem.

Segundo o site TIOBE (Programming Community Index Definition), o C# é uma das 5 linguagens mais utilizadas no mundo! Além disso, grandes empresas utilizam o C# em seus produtos, empresas como Microsoft (em uma infinidade de soluções: desde soluções Web até soluções mobile multiplataforma através do Xamarin), Amazon, StackOverflow (toda a stack web do StackOverflow é construída em cima de C# e .NET) e nós aqui no TreinaWeb (algumas de nossas aplicações foram escritas com C# e .NET Framework Full e .NET Core). Você pode até mesmo desenvolver jogos com C# através da Unity.

Então, se você estudá-la e se especializar, certamente não ficará fora do mercado. =D

Como aprender C#?

Aqui no TreinaWeb temos uma trilha voltada para C#. O curso de “C# Básico” é ótimo para você dar os primeiros passos nessa linguagem de fácil compreensão e com recursos poderosos. No curso básico, além de você aprender todos os conceitos básicos dessa linguagem, você acompanhará a construção de um projeto com todo o seu passo a passo.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Conheça nossa metodologia

Nosso ambiente de aprendizagem é 100% online. Nossa metodologia de ensino é baseada em vídeo aulas, apostilas, exercícios aula-a-aula e exemplos completos. Você estuda no seu tempo e ao final pode baixar o seu certificado digital ou solicitar o certificado impresso.

Na parte escrita, fornecemos um material totalmente atualizado e completo para que você possa usufruir do conteúdo, utilizando-se de textos e imagens. Já as vídeo-aulas são bem explicativas e práticas, abordando todo o conteúdo passo-a-passo, para que você entenda tudo da melhor maneira possível.

Além disso, você encontrará exercícios para poder fixar, praticar e aplicar todo o conteúdo aprendido. São exercícios que são propostos em cada aula do curso. Eles podem variar entre alguns formatos, como por exemplo questões de escolha única, questões de múltipla escolha e complemento de trechos de código.

Se ainda assim você tiver alguma dúvida, você poderá pedir ajuda aos nossos professores através de tickets de atendimento. Funciona como um canal direto entre você e o professor, onde você poderá realizar perguntas que serão respondidas muito brevemente!

Além disso, ainda pelo sistema suporte, você também poderá consultar todas as perguntas que já foram respondidas a outros alunos! =)

Quais conhecimentos preciso ter para iniciar este curso?

O curso é recomendado para você iniciar seus estudos na linguagem C#, no entanto, é interessante saber as bases necessárias para aprender qualquer linguagem de programação: “Lógica de Programação” e “Lógica de Programação Orientada a Objetos”.

Também ministramos esses cursos:

Lógica de Programação Completo
Curso de Lógica de Programação Completo
CONHEÇA O CURSO
Lógica Orientada a Objetos Completo
Curso de Lógica Orientada a Objetos Completo
CONHEÇA O CURSO

Gostou do que viu?

Se entusiasmou com a linguagem? Gostaria de conhecê-la com mais detalhes? Sim, você pode dar uma espiadinha. Acesse o link do curso de C# Básico e veja algumas aulas de exemplo. =D

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Bons estudos!

Aplicações self-contained com o .NET Core

Algumas aplicações necessitam que as plataformas utilizadas sejam instaladas nas máquinas hosts. Exemplos disso são o Java Virtual Machine e o .NET Framework. Se você já programou para estas plataformas, sabe que a aplicação pode requerer que o .NET ou JVM estejam instalados para que ela rode.

Esse comportamento pode ser contornado criando-se uma aplicação self-contained. Aplicações self-contained, são as que já contêm o ambiente necessário para que ela seja executada.

Neste artigo veremos como criar uma aplicação self-contained com o .NET Core.

C# (C Sharp) - Introdução ao ASP.NET Core
Curso de C# (C Sharp) - Introdução ao ASP.NET Core
CONHEÇA O CURSO

Criando a aplicação

Para exemplificar uma aplicação self-contained, primeiro temos que criar uma aplicação de exemplo. Ela poderia ser qualquer um dos tipos de aplicações suportados pelo .NET Core, mas para este artigo vou criar uma aplicação MVC:

dotnet new mvc -n App

Na aplicação criada é importante aplicar o restore:

dotnet restore

Compilar:

dotnet build

E executar para ver se está tudo certo:

dotnet run

Com a aplicação funcionando, podemos criar uma versão self-contained dela.

Criando uma aplicação self-contained

Para se definir que uma aplicação é self-contained é necessário fazer apenas uma pequena modificação nela. No arquivo .csproj, é necessário adicionar no elemento <PropertyGroup> a plataforma alvo. Por exemplo:

<PropertyGroup>
  <TargetFramework>netcoreapp1.1</TargetFramework>
  <RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>

Acima é definido que a plataforma alvo da aplicação é o ambiente Windows 10 de 64bits. Após isso, é necessário aplicar o restore na aplicação:

dotnet restore

E informar esta plataforma na hora da publicação dela:

dotnet publish -c release -r win10-x64

Com isso, será gerado um arquivo .exe:

Que ao ser executado, irá iniciar a aplicação:

Caso queria definir outros ambientes para a aplicação, eles podem ser informados à tag <RuntimeIdentifiers> separados por ponto e vírgula:

<PropertyGroup>
  <TargetFramework>netcoreapp1.1</TargetFramework>
  <RuntimeIdentifiers>win10-x64;osx.10.12-x64;ubuntu.17.04-x64</RuntimeIdentifiers>
</PropertyGroup>

E depois de aplicar o restore:

dotnet restore

Basta informar para qual plataforma a aplicação deve ser gerada:

Mac OS X:

dotnet publish -c release -r osx.10.12-x64

Ubuntu:

dotnet publish -c release -r ubuntu.17.04-x644

Só é importante ficar atento se a plataforma alvo é suportada pelo .NET Core, caso contrário não vai funcionar.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Recursos de linha de comando para o Entity Framework Core

É inegável o quão poderoso é o Visual Studio. Ele possui vários recursos que facilitam (e muito) o desenvolvimento. Mas, com o advento do .NET Core, e a possibilidade de criar a aplicação em qualquer plataforma, alguns desses recursos fazem falta em algumas delas.

Um desses recursos é o “Package Manager Console”, que além de permitir adicionar packages NuGet, também permite executar comandos para certos pacotes, como habilitar as migrations do Entity Framework.

Caso deseje desenvolver a sua aplicação em uma plataforma diferente do Windows (ou não queira utilizar o Visual Studio), o “Package Manager Console” deve ser substituído por comandos do .NET CLI, e neste artigo conheceremos os comandos do Entity Framework Core.

Organizando a casa

Os comandos do .NET CLI só estão disponíveis no SDK do .NET Core, então para executar os comandos que apresentarei a seguir, é necessário instalar este SDK no seu computador.

Além disso, os comandos só estão disponíveis para projetos definidos para uma das versões abaixo do .NET:

  • .NET Framework 4.5.1 ou superior (“net451”, “net452”, “net46”, etc.)
  • .NET Core App 1.0 ou superior (“netcoreapp1.0”, “netcoreapp1.1”, etc.)
Desenvolvedor C# Pleno
Formação: Desenvolvedor C# Pleno
A formação Desenvolvedor C# nível Pleno da TreinaWeb tem um enfoque sobre a conectividade entre o .NET Framework e os bancos de dados relacionais através do ADO.NET. Também serão abordados os recursos para desenvolvedores que o Oracle e o MySQL oferecem, como functions, stored procedures e triggers.
CONHEÇA A FORMAÇÃO

Preparando o palco

Com o ambiente organizado, você já poderá criar uma aplicação por linha de comando utilizando o .NET Core:

dotnet new console -o ExemploEntityCore

A aplicação criada com o comando acima, é uma aplicação de console simples. Ao acessar a pasta dela, é possível adicionar um pacote do NuGET pelo terminal:

dotnet add package Microsoft.EntityFrameworkCore.Design

O pacote Microsoft.EntityFrameworkCore.Design é quem adiciona as ferramentas de linha de comando para o Entity Framework Core. Assim, para elas funcionarem, é necessário executar o comando restore:

dotnet restore

Colocando a mão na massa

Adicione uma entidade na aplicação, como a abaixo:

public class Cliente {
    public int Id { get; set; }
    public string Nome { get; set; }
    public int Idade { get; set; }
}

Assim, é possível criar o DBContext com o comando abaixo:

dotnet ef dbcontext scaffold "Data Source=clientes.db" Microsoft.EntityFrameworkCore.SQLite -c "ClientesDbContext"

Ele irá criar a classe ClientesDbContext, que herdará DBContext, além de já configurar a string de conexão "Data Source=clientes.db", para o provider Microsoft.EntityFrameworkCore.SQLite.

Observação: Os pacotes Microsoft.EntityFrameworkCore.SQLite e Microsoft.EntityFrameworkCore.SQLite.Design deve ser adicionados na aplicação.

Se o comando “dotnet-ef” apresentar algum problema, verifique se foi adicionada a referência abaixo. Se não, adicione-a manualmente:

<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0 " />
</ItemGroup>

Com o DbContext criado, adicione nele a entidade:

public DbSet<Cliente> Clientes { get; set; }

Que será possível adicionar migrations na aplicação:

dotnet ef migrations add CriaBase

Caso não tenha gostado do resultado, e queira desfazer a ação, pode ser utilizado comando:

dotnet ef migrations remove

Ele sempre irá remover a última migration criada.

Com uma migration definida, é possível executá-la com o comando:

dotnet ef database update

Como a nossa migration inicial cria a base de dados, ele pode ser desfeito com o comando abaixo:

dotnet ef database drop

Que exclui a base de dados.

Caso a entidade seja alterada:

public class Cliente {
    public int Id { get; set; }
    public string Nome { get; set; }
    public int Idade { get; set; }
    public char Sexo { get; set; }
}

É possível adicionar uma nova migration:

dotnet ef migrations add AddColumnSexo

E atualizar novamente a base de dados:

dotnet ef database update
Desenvolvedor ASP.NET Full-Stack
Formação: Desenvolvedor ASP.NET Full-Stack
A formação Desenvolvedor ASP.NET Full Stack da TreinaWeb tem como objetivo abordar as duas principais plataformas dentro do ASP.NET: o ASP.NET MVC, para criação de aplicações web seguindo o padrão MVC/MVW; e o ASP.NET WebAPI, para criação de APIs RESTful que sigam os padrões mais atuais da indústria.
CONHEÇA A FORMAÇÃO

Conclusão

Como foi possível notar, o CLI do Entity Core é muito similar ao realizado no “Package Manager Console”. Então, caso você já esteja acostumado a utilizá-lo no Visual Studio, não terá dificuldade para fazer uso dele pelo terminal. Mas em caso de dúvida, você pode informar o parâmetro --help para obter mais informações sobre cada comando.

Pattern Matching no C# 7.0

O operador is existe desde a primeira versão do C# e ele sempre foi utilizado para verificar o tipo de um objeto em tempo de execução.

DaVinci Resolve - OFX Filtros e Efeitos
Curso de DaVinci Resolve - OFX Filtros e Efeitos
CONHEÇA O CURSO

Neste tipo de verificação é muito comum o uso de operações “cast“. Por exemplo, vamos supor uma classe base, com duas classes filhas:

public class Forma() {}

public class Triangulo : Forma{
    public int Largura { get; set; }
    public int Altura { get; set; }
    public int Base { get; se; }

    public Triangulo(int largura, int altura, int base) {
        this.largura = largura;
        this.altura = altura;
        this.base = base;
    }

    public void Perimetro (){
        Console.WriteLine("O perímetro do triângulo é {0}", largura + altura + base);
    }
}

public class Retangulo : Forma {
    public int Largura { get; set; }
    public int Altura { get; set; }

    public Retangulo(int largura, int altura) {
        this.largura = largura;
        this.altura = altura;
    }

    public void Area(){
        Console.WriteLine("A área do retângulo é {0}", largura * altura);
    }
}

Caso houvesse uma array com essas classes, para chamar cada método delas, seria necessário realizar uma conversão:

public class Program {
    public static void Main(){
        Forma[] formas = { new Triangulo(10, 12, 10), new Retangulo(7, 4), new Triangulo(17, 15, 16), new Retangulo(25, 12) };

        foreach (var item in formas)
        {
            if (item is Triangulo)
                ((Triangulo)item).Perimetro();
            if (item is Retangulo)
                ((Retangulo)item).Area();
        }
    }
}

Repare que ao descobrir o tipo da variável, ainda é necessário realizar o cast:

if (item is Triangulo)
    ((Triangulo)item).Perimetro();

Para evitar este cast, no C# 7.0 foi introduzido o conceito de Pattern Matching:

Pattern Matching

O Pattern Matching adiciona mais poder ao operador is e a cláusula switch.

Agora com o operador is, após realizar uma verificação de tipo, é possível atribuir o resultado a uma variável:

public class Program {
    public static void Main(){
        Forma[] formas = { new Triangulo(10, 12, 10), new Retangulo(7, 4), new Triangulo(17, 15, 16), new Retangulo(25, 12) };

        foreach (var item in formas)
        {
            if (item is Triangulo t)
                t.Perimetro();
            if (item is Retangulo r)
                r.Area();
        }
    }
}

Com isso, não é mais necessário realizar o cast do objeto dentro do condicional. Este tipo de situação também nos permite uma verificação mais elaborada:

if (item is Retangulo r and r.Largura > 0)
    r.Area();

Assim, apenas se item for um objeto de Retangulo e a propriedade Largura deste objeto for maior que 0, que o bloco do condicional será executado.

Não temos essas situações no exemplo acima, mas agora com o operador is também é possível verificar um valor literal:

if(item is 10)
    Console.WriteLine("Item é 10");

Null:

if(item is null)
    Console.WriteLine("Item é nulo");

Ou mesmo aplicar o objeto a uma variável:

if(item is var i)
    Console.WriteLine("Item é do tipo {0}", i?.GetType().Name);

Desta forma, é possível descobrir o tipo do objeto quando esta informação não é conhecida.

Pattern Matching com switch

Além do operador is, o switch também recebeu novos recursos para ser aplicado Pattern Matching. Agora é possível comparar o tipo de um objeto dentro de um bloco switch:

foreach (var item in formas)
{
    switch(item){
        case Triangulo t:
            t.Perimetro();
            break;
        case Retangulo r:
            r.Area();
            break;
        case 10:
            Console.WriteLine("Item é 10");
            break;
        case null:
            Console.WriteLine("Item é nulo");
            break;
        case Retangulo r when r.Largura > 0:
            r.Area();
            break;
        case var i:
            Console.WriteLine("Item é do tipo {0}", i?.GetType().Name);
            break;
    }
}

Algumas das opções acima não se aplicam ao nosso exemplo, mas elas foram adicionadas para mostrar que as mesmas opções que vimos com o condicional if, podem ser aplicadas ao switch.

Conclusão

Agora o processo de checagem de tipo e cast de objetos está mais simples e dinâmico. Assim, caso esteja utilizando a versão 7.0 do C#, não hesite em utilizar este recurso. Ele irá melhorar a legibilidade do seu código.

DaVinci Resolve - OFX Filtros e Efeitos
Curso de DaVinci Resolve - OFX Filtros e Efeitos
CONHEÇA O CURSO

Ref Returns no C# 7

Continuando com a série de artigos sobre novidades do C# 7, hoje conheceremos o Ref Returns.

Passagem por valor e por referência

Desde de o seu início, o C# possui duas formas de passagem de variáveis para um método, por valor e por referência.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Passagem por valor significa que apenas o valor da variável será passado para o método. Caso este valor seja alterado dentro do método, isso não irá refletir na variável passada:

static void Main(string[] args)
{
    int i = 10;
    PassagemPorValor(i);
    Console.WriteLine($"Após chamar o método, {nameof(i)} = {i}");
}

static void PassagemPorValor(int j)
{
    j = 20;
}

Já na passagem por referência, é passada a referência da variável para o método. Ou seja, é passado o endereço da memória, assim, dentro desse contexto, caso ela seja alterada, isso será refletido na variável passada:

static void Main(string[] args)
{
    int i = 10;
    PassagemPorValor(ref i);
    Console.WriteLine($"Após chamar o método, {nameof(i)} = {i}");
}

static void PassagemPorValor(ref int j)
{
    j = 20;
}

Você provavelmente já conhece essas duas formas de passagem de variáveis, pois isso é abordado (ou deveria ser) em todo curso básico da linguagem.

É necessário revisar este ponto, pois uma coisa precisa ficar bem clara: quando o ref é utilizado, trabalha-se com a referência da variável, o seu espaço de memória. Podemos até dizer que ref funciona como os ponteiros de C/C++ (para quem conhece).

Ref Local

Antes de vermos a parte principal deste artigo, é bom mencionar que agora no C# 7, o ref pode ser utilizado na declaração de uma variável:

int i = 1;
ref int j = ref i;
j = 2;

Console.WriteLine($"A variável {nameof(i)} foi alterada para: {i}");

Assim como na passagem por referência, a variável j está recebendo o endereço de memória de i. Dessa forma, quando o valor de j for alterado, o valor de i também será.

Ref Return

O último recurso que o C# 7 adicionou ao ref foi a possibilidade de retornar a referência de uma variável.

Vamos a um exemplo para ficar mais claro:

public class Exemplo
{
    private int variavel = 0;

    public int ObterValor() => variavel;

    public ref int ObterReferencia()
    {
        return ref variavel;
    }
}

Note que dentro do método ObterReferencia o método está retornando à referência da variável:

return ref variavel;
C# (C Sharp) Intermediário
Curso de C# (C Sharp) Intermediário
CONHEÇA O CURSO

Assim, quem chamar este método para utilizar uma variável Ref Local para armazenar a referência retornada e modificar o valor da variável:

var exemplo = new Exemplo();

ref int referencia = exemplo.ObterReferencia();
referencia++;

Console.WriteLine(exemplo.ObterValor());

Como as variáveis locais são removidas da memória quando o método é finalizado, não é possível aplicar o ref return em uma variável local:

public ref int RetornarPorReferencia()
{
    int x = 10;
    return ref x;
}

Mas, objetos que são armazenados na memória heap, como um array, podem ter suas referências retornadas, mesmo que eles sejam declarados dentro do método:

public ref int RetornarPorReferencia()
{
    int[] arr = { 1, 2, 3, 4 };
    return ref arr[0];
}

O código acima também poderia ser da seguinte forma:

public ref int RetornarPorReferencia()
{
    int[] arr = { 1, 2, 3, 4 };
    ref int x = ref arr[0];
    return ref x;
}

Que o resultado seria o mesmo.

Por fim, um parâmetro passado por referência, pode ser retornado por referência:

public ref int RetornarPorReferencia(ref int x)
{
    x = 2;
    return ref x;
}
C# (C Sharp) Avançado
Curso de C# (C Sharp) Avançado
CONHEÇA O CURSO

Conclusão

Apesar de ser antigo na linguagem, o modificador ref estava sendo subutilizado. Com os recursos ref local e ref return, ele ganha mais poder, permitindo que os programadores tenham acesso a memória, sem que isso torne a aplicação menos segura.

Mesmo sendo recursos úteis, há de se reconhecer que ref local e ref return são limitados a situações especificas. Então, caso você tenha um problema que se enquadre no seu uso, claro, não hesite em utilizá-lo.

As mudanças de Expression-bodied members no C# 7

Na versão 3.0 do C# surgiram as expressões lambda, como uma parte do LINQ. Na prática, elas não passam de funções anônimas, que dispensam a implementação no corpo da classe de operações simples, geralmente com apenas uma instrução.

Concebidas para simplificar e facilitar a codificação das aplicações, até a versão 5.0 do C#, elas eram utilizadas apenas dentro do corpo dos métodos de uma classe. Mas na versão 6.0 foi introduzido um novo recurso chamado Expression-bodied Members.

C# (C Sharp) Básico
Curso de C# (C Sharp) Básico
CONHEÇA O CURSO

Em um passado não muito distante …

O Expression-bodied Members introduzido no C# 6.0 passou a permitir que expressões semelhantes às expressões lambdas fossem utilizadas para definir métodos ou propriedades somente leitura que contenham apenas uma instrução.

Por exemplo, vamos supor uma classe Pessoa que possua a estrutura abaixo:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get { return nome; }
        set { nome = value; }
    }

    public string Sobrenome
    {
        get { return sobrenome; }
        set { nome = value; }
    }

    public DateTime DataNascimento
    {
        get { return dataNascimento; }
        set { dataNascimento = value; }
    }

    public string NomeCompleto
    {
        get { return nome + " " + sobrenome; }
    }

    public int Idade()
    {
        return (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
    }
}

Com o expression-bodied properties, uma propriedade somente leitura:

public string NomeCompleto
{
    get { return nome + " " + sobrenome; }
}

Pode ser alterada para:

public string NomeCompleto => nome + " " + sobrenome;

E com o expression-bodied methods, o método Idade:

public int Idade()
{
    return (DateTime.Now.Year - dataNascimento.Year - 1) +
        (((DateTime.Now.Month > dataNascimento.Month) ||
        ((DateTime.Now.Month == dataNascimento.Month) && 
        (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Pode ser modificado para:

public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
                (((DateTime.Now.Month > dataNascimento.Month) ||
                ((DateTime.Now.Month == dataNascimento.Month) && 
                (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);

É importante frisar que em ambos os exemplos acima os blocos continham return, mas em um método sem isso:

public void Imprimir()
{
    Console.WriteLine(Nome + " " + Sobrenome);
}

Também pode ser aplicado o expression-bodied:

public void Imprimir() => Console.WriteLine(Nome + " " + Sobrenome);

O importante é que o método e propriedade somente leitura contenha uma instrução de uma linha.

Voltando ao presente

Já na versão 7 do C# foram introduzidos mais três recursos ao expression-bodied. Vamos modificar a classe apresentada anteriormente para mostrá-los:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get { return nome; }
        set { nome = value; }
    }

    public string Sobrenome
    {
        get { return sobrenome; }
        set { nome = value; }
    }

    public DateTime DataNascimento
    {
        get { return dataNascimento; }
        set { dataNascimento = value; }
    }

    public string NomeCompleto => nome + " " + sobrenome;

    public Pessoa() { }

    public Pessoa(string nome)
    {
        this.nome = nome;
    }

    ~Pessoa()
    {
        Console.WriteLine("Classe sendo destruída!");
    }

    public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Note que agora temos métodos construtores e o destrutor da classe. E é nesses métodos que a partir da versão 7, pode ser aplicado, respectivamente, o expression-bodied constructors, e o o expression-bodied destructors.

O processo é o mesmo, ambos os métodos precisam conter apenas uma instrução:

public Pessoa(string nome)
{
    this.nome = nome;
}

~Pessoa()
{
    Console.WriteLine("Classe sendo destruída!");
}

Para expression-bodied ser aplicado:

public Pessoa(string nome) => this.nome = nome;

~Pessoa() => Console.WriteLine("Classe sendo destruída!");

Além do construtor e destrutor, o expression-bodied agora pode ser aplicado aos acessores das propriedades:

public string Nome
{
    get => nome;
    set => nome = value;
}

Agora que a auto propriedade (disponível desde a versão 2 do C#) ainda é a melhor opção para reduzir código:

public string Nome { get; set; }

Mas, caso seja implementada a interface INotifyPropertyChanged, o uso deste recurso é bom para reduzir o código:

public string Nome
{
    get => nome;
    set => SetProperty(ref nome, value);
}

Não tem esse exemplo na classe acima, mas este mesmo princípio que permite o uso do expression-bodied nos acessores das propriedades, pode ser aplicado aos eventos:

private EventHandler _someEvent;
public event EventHandler SomeEvent
{
    add => _someEvent += value;
    remove => _someEvent -= value;
}

Mas este também tem a sua versão mais simples:

public event EventHandler SomeEvent

Introduzida na versão 6.

Para finalizar, aplicando os conceitos acima à classe Pessoa, ela ficará com a estrutura abaixo:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get => nome;
        set => SetProperty(ref nome, value);
    }

    public string Sobrenome
    {
        get => sobrenome;
        set => nome = value;
    }

    public DateTime DataNascimento
    {
        get => dataNascimento;
        set => dataNascimento = value;
    }

    public string NomeCompleto => nome + " " + sobrenome;

    public Pessoa() { }

    public Pessoa(string nome) => this.nome = nome;

    ~Pessoa() => Console.WriteLine("Classe sendo destruída!");

    public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Conclusão

Assim como demonstrado com as tuplas, o C# 7.0 está introduzindo recursos que visam melhorar a produtividade dos desenvolvedores, sejam novos, como as já referidas tuplas ou com melhorias de recursos já existentes, como é o caso do expression-bodied.

C# (C Sharp) - Introdução ao ASP.NET Core
Curso de C# (C Sharp) - Introdução ao ASP.NET Core
CONHEÇA O CURSO

© 2004 - 2019 TreinaWeb Tecnologia LTDA - CNPJ: 06.156.637/0001-58 Av. Paulista, 1765, Conj 71 e 72 - Bela Vista - São Paulo - SP - 01311-200