Boas-vindas! Meu nome é André Bessa, serei seu instrutor ao longo deste treinamento, em que vamos estudar bibliotecas de DLLs.
André Bessa é um homem negro de rosto arredondado, com cabelo baixo e barba por fazer. Veste uma camiseta rosa claro e está em um ambiente com iluminação azul suave. Ao fundo, há uma estante de ferro com livros e outros objetos, e uma parede com dois pôsteres.
Este curso é voltado para pessoas que já conhecem a linguagem C# e desejam se aprofundar nos estudos, aprendendo a compartilhar componentes entre projetos. Para melhor aproveitamento deste curso, é recomendado que você já tenha os conhecimentos sobre fundamentos da linguagem C# e do paradigma de programação orientada a objetos.
Continuaremos a atender nosso cliente fictício, o banco virtual Bytebank. No decorrer do curso, vamos aprender sobre:
Ao final, teremos um componente no formato de uma DLL, que poderá ser reaproveitado em outras soluções.
Espero que você esteja animado! Vamos estudar?
Para iniciar nossos estudos, vamos fazer o download do projeto inicial. Trata-se do mesmo projeto console que usamos no treinamento de C# sobre arrays e coleções.
De início, vamos rodar a aplicação para conferir as funcionalidades disponíveis. Clicando no ícone de play no menu superior do Visual Studio, o programa será executado no console, onde aparecerá o menu principal, com opções de 1 a 6. Esse projeto visa atender o gerente de contas do Bytebank, permitindo:
Voltando ao Visual Studio, vamos pressionar "Ctrl + Alt + L" para abrir o gerenciador de soluções na lateral direita da IDE. Nesse projeto, há uma série de namespaces, cada um com sua funcionalidade.
Um desses namespaces é o "bytebank.Modelos", onde constam os modelos das classes de funcionários, parceiros comerciais, utilitários, conta-corrente, entre outros. Especificamente nessa solução, estamos trabalhando somente com a classe ContaCorrente
, responsável pelas funcionalidades que conferimos há pouco (cadastro, listagem etc).
Após algumas discussões, nós da equipe de desenvolvimento do Bytebank chegamos à conclusão que o namespace "bytebank.Modelos" pode ser reutilizado em outros projetos. Há outras soluções rodando em paralelo que também poderiam fazer uso das classes Funcionario
, Cliente
e ContaCorrente
, por exemplo.
Portanto, nosso objetivo é descobrir uma maneira de reaproveitar esse namespace em outros projetos. Precisamos de um projeto compartilhado, um pacote de classes que possa ser consumido por outras soluções.
Com tudo isso mente, vamos desenvolver um novo tipo de projeto que conterá essas classes. Podemos criá-lo em uma nova instância do Visual Studio ou dentro da própria solução. No caso, seguiremos pela segunda opção.
Quando iniciamos um projeto no Visual Studio — por exemplo, de console, API ou Windows Forms —, sempre criamos uma solução e, dentro dessa solução, temos o nosso projeto. Uma solução pode ter mais de um projeto e é isso que faremos a seguir.
No gerenciador de soluções, clicaremos com o botão direito do mouse sobre a solução "bytebank_ATENDIMENTO" e selecionaremos "Adicionar > Novo Projeto...". Uma nova janela será aberta.
Esse projeto conterá somente as classes que serão consumidas por outros projetos do Bytebank. Então, selecionaremos a opção "Biblioteca de Classes". Na parte superior da tela, há um campo de pesquisa que pode nos auxiliar a filtrar essa opção. Após selecioná-la, pressionaremos o botão "Próximo" no canto inferior direito.
No campo "Nome do projeto", digitaremos "bytebank_Modelos". Assim, mantemos a uniformidade entre os nomes dos projetos dessa solução. Em seguida, clicaremos em "Próximo" novamente. Na nova tela, vamos manter o framework ".NET 6.0" selecionado e pressionar o botão "Criar" no canto inferior direito.
Ao criar esse projeto na nossa solução, será gerado automaticamente um arquivo chamado Class1.cs
, em branco. Vamos excluí-lo do nosso projeto.
Nosso primeiro objeto é transferir o namespace "bytebank.Modelos" para o nosso projeto "bytebank_Modelos". No gerenciador de soluções, vamos clicar com o botão direito sobre "bytebank.Modelos" e selecionar "Recortar" (ou usar o atalho "Ctrl + X"). Em seguida, clicaremos com o botão direito sobre "bytebank_Modelos" e selecionaremos "Colar" ("Ctrl + V"). Pronto, a primeira etapa já foi feita!
O projeto bytebank_Modelos conterá as classes referentes aos modelos usados nos projetos do Bytebank, como ContaCorrente
e Funcionarios
. Outras classes que venham a ser criadas também serão adicionadas nessa biblioteca, que será utilizada para diversos projetos do Bytebank.
Na sequência, vamos compilar nossa solução para gerar um executável e checar se há qualquer tipo de erro. No gerenciador de soluções, clicaremos com o botão direito sobre a solução e selecionar "Recompilar Solução". No painel inferior do Visual Studio, aparecerá uma lista com 12 erros. Como movemos um namespace para outro projeto (na mesma solução), as referências ao "bytebank.Modelos" não funcionam mais.
Como exemplo, podemos abrir o arquivo ByteBankAtendimento.cs
. Essa classe, que encapsula as funcionalidades de atendimento para montar o menu, não reconhece mais onde encontrar a classe ContaCorrente
! Para resolver esse problema, é preciso que o projeto bytebank_ATENDIMENTO consiga reconhecer o projeto bytebank_Modelos.
Então, no bytebank_ATENDIMENTO, temos que referenciar o projeto bytebank_Modelos. No gerenciador de soluções, imediatamente abaixo do projeto bytebank_ATENDIMENTO, vamos clicar em "Dependências" e selecionar "Adicionar Referência de Projeto...". Uma nova janela será aberta, onde estará listado o projeto bytebank_Modelos, pois estamos dentro da mesma solução. Vamos selecionar a caixa à esquerda dele e, em seguida, pressionar o botão "OK" no canto inferior direito.
Ao clicar no projeto bytebank_ATENDIMENTO, o Visual Studio abrirá o arquivo bytebank_ATENDIMENTO.csproj
, que contém as configurações do nosso projeto, como a versão do .NET. Abaixo de <ItemGroup>
, foi adicionada a referência para o bytebank_Modelos:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\bytebank_Modelos\bytebank_Modelos.csproj" />
</ItemGroup>
</Project>
Após salvar essa alteração, vamos recompilar nossa solução. Dessa vez, não teremos erros e nossa solução voltará a funcionar. Nós removemos o namespace referente aos modelos, adicionamos uma biblioteca de classes à solução e incluímos a referência a essa biblioteca no projeto bytebank_ATENDIMENTO.
Para nos certificar de tudo continua funcionando normalmente, podemos rodar a aplicação. No menu, vamos digitar "2" e pressionar "Enter" para conferir a lista de clientes iniciais do programa, por exemplo.
Portanto, a nossa meta é reaproveitar essa biblioteca em outros projetos. Nós já criamos uma biblioteca de classes com modelos do nosso negócio e, na sequência, podemos encapsular algumas funcionalidades nela.
Existem bibliotecas de classes com funções bem específicas, por exemplo: manipulação um arquivo ou acesso a um banco de dados. Uma vez que entendermos como criar uma biblioteca de classes e o que podemos encapsular nela, exploraremos como utilizar bibliotecas de terceiros para adicionar mais funcionalidades ao nosso projeto bytebank_ATENDIMENTO.
Acabamos de criar nosso primeiro projeto de biblioteca, chamado bytebank_Modelos. Ele contém as classes referentes aos modelos que podem ser utilizados em projetos internos do Bytebank. Por exemplo, na pasta "Conta", temos as classes ContaCorrente
e Cliente
. Já na parte administrativa (pasta "ADM"), temos Funcionario
, Auxiliar
, Desenvolvedor
, Designer
, Diretor
e assim em diante.
Contudo, uma biblioteca de classes não contempla apenas modelos que podem ser reaproveitados. Também é possível incluir funcionalidades, como a opção de gerar um arquivo TXT ou de nos conectar a um banco de dados específico.
A partir dessas bibliotecas, conseguimos montar nosso projeto como se fosse um LEGO, em que cada peça tem sua função — uma biblioteca gerará arquivos, outra conectará ao banco de dados, outra implementará a interface gráfica etc.
Há uma nova demanda para o projeto bytebank_ATENDIMENTO. Precisamos gerar um arquivo no formato JSON com todas as contas cadastradas no nosso sistema, para ser enviado ao Banco Central. Nós poderíamos criar uma biblioteca responsável por esse processo, mas será que já não existe uma que faça isso? Vamos pesquisar.
O NuGet é um repositório de pacotes de bibliotecas da plataforma .NET em que podemos pesquisar se existe uma biblioteca com a função que precisamos. No menu superior do Visual Studio, vamos acessar "Ferramentas > Gerenciador de Pacotes do NuGet > Gerenciar Pacotes do NuGet para a Solução". Também podemos trabalhar na linha de comando, usando CLI.
Na aba "Procurar", selecionaremos o pacote Newtonsoft.Json, por James Newton-King (provavelmente a primeira opção da lista). Se necessário, você pode utilizar a barra de pesquisa no topo da tela, pressionando "Ctrl + L".
No vídeo, estamos instalando a versão 13.0,1, a mais recente no momento de gravação deste curso.
Ao selecionar o pacote, será aberto um painel à direita com uma lista de nossos projetos. Vamos marcar a caixa referente ao bytebank_ATENDIMENTO para instalar a biblioteca nele. Em seguida, pressionaremos o botão "Instalar" na parte direita inferior da lista.
Aparecerá uma mensagem na tela e, para confirmar a alteração do projeto, clicaremos em "OK" no canto inferior direito. O primeiro indício de que a instalação foi finalizada é que o botão "Desinstalar" será habilitado, imediatamente acima do botão "Instalar" que pressionamos há pouco.
Acabamos de instalar o pacote Newtonsoft, que trabalhará com o formato JSON. Já podemos fechar a aba do gerenciador do NuGet.
Para implementar a nova funcionalidade, precisamos conhecer nosso projeto. Vamos acessar o arquivo ByteBankAtendimento.cs
, que encapsula as funções do nosso projeto atual.
De início, essa classe cria uma lista interna de contas já cadastradas para facilitar nosso trabalho. Em seguida, temos o menu com 6 opções — cadastrar, listar, remover, ordenar, pesquisar contas e sair do sistema. Vamos adicionar a funcionalidade de exportação de contas no menu e incluir um novo case
na estrutura switch
, com o método ExportarContas()
. Além disso, na definição do while
, substituiremos (opcao != '6')
por (opcao != '7')
:
// ...
public void AtendimentoCliente()
{
try
{
char opcao = '0';
while (opcao != '7')
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== Atendimento ===");
Console.WriteLine("===1 - Cadastrar Conta ===");
Console.WriteLine("===2 - Listar Contas ===");
Console.WriteLine("===3 - Remover Conta ===");
Console.WriteLine("===4 - Ordenar Contas ===");
Console.WriteLine("===5 - Pesquisar Conta ===");
Console.WriteLine("===6 - Exportar Conta ===");
Console.WriteLine("===7 - Sair do Sistema ===");
Console.WriteLine("===============================");
Console.WriteLine("\n\n");
Console.Write("Digite a opção desejada: ");
try
{
opcao = Console.ReadLine()[0];
}
catch (Exception excecao)
{
throw new ByteBankException(excecao.Message);
}
switch (opcao)
{
case '1':
CadastrarConta();
break;
case '2':
ListarContas();
break;
case '3':
RemoverContas();
break;
case '4':
OrdenarContas();
break;
case '5':
PesquisarContas();
break;
case '6':
ExportarContas();
break;
case '7':
EncerrarAplicacao();
break;
default:
Console.WriteLine("Opcao não implementada.");
break;
}
}
}
catch (ByteBankException excecao)
{
Console.WriteLine($"{excecao.Message}");
}
}
// ...
O Visual Studio indicará um erro em ExportarContas()
porque esse método ainda não existe. Vamos desenvolvê-lo, a seguir.
Posicionando o cursor sobre ExportarContas()
, podemos pressionar "Ctrl + ." ou clicar no ícone de lâmpada amarela que aparece à esquerda dessa linha e, em seguida, selecionar "Gerar método 'ExportarContas'". Logo abaixo do while
, teremos a seguinte estrutura:
private void ExportarContas()
{
throw new NotImplementedException();
}
Vamos adaptá-la:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
}
Seguindo o padrão dos demais métodos nesse arquivo, primeiramente imprimimos um cabeçalho. Em seguida, temos uma estrutura if
para fazer uma validação. Se a _listaDeContas
(isto é, o objeto que contém as contas cadastradas) for menor ou igual a 0, exibimos uma mensagem de que não há dados para exportação. Do contrário, trabalharemos com o JSON.
Então, vamos desenvolver o else
. A princípio, criaremos uma variável do tipo string chamada json
e usaremos a biblioteca Newtonsoft. Nela, temos a classe JsonConvert
, que possui o método SerializeObject()
:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject();
}
}
Esse método é responsável pela serialização, por transformar um objeto em outro formato para que ele seja persistido em um arquivo ou em uma base de dados ou seja transferido para outro sistema. Vale lembrar que também existe o caminho contrário: a desserialização, em que retornamos um formato específico como um objeto.
O método SerializeObject()
receberá como parâmetro a nossa lista de contas e o formato:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
}
}
Quando trabalhamos com bibliotecas de terceiros, é interessante consultar a documentação para conhecer suas funcionaliades e descobrir como utilizá-las. A documentação do Newtonsoft, por exemplo, está disponível tanto no repositório do NuGet quanto no site oficial da biblioteca.
Em seguida, vamos criar um arquivo. Usaremos a FileStream
, uma bliblioteca do .NET para fazer operações de leitura e escrita de arquivos nos diretórios da própria máquina.
Para tratar possíveis exceções nesses processos de leitura e escrita, vamos desenvolver uma estrutura try/catch
:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
try
{
}
catch (Exception)
{
throw;
}
}
}
No bloco try
, criaremos um FileStream
chamado fs
. Exportaremos o arquivo para o caminho c:\tmp\export\contas.json
. Como se trata de criação de arquivo, usaremos o FileMode.Create
:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
try
{
FileStream fs = new FileStream(@"c:\tmp\export\contas.json",
FileMode.Create);
}
catch (Exception)
{
throw;
}
}
}
Lembre-se de criar o caminho
c:\tmp\export\
na sua máquina. Do contrário, ocorrerá um erro na execução da aplicação.
Na sequência, usaremos a estrutura using
para escrever nesse arquivo. Desse modo, criaremos um objeto e o descartaremos após sua utilização. Vamos criar um StreamWriter
chamado streamwriter
. Como parâmetro, passaremos o fs
:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
try
{
FileStream fs = new FileStream(@"c:\tmp\export\contas.json",
FileMode.Create);
using (StreamWriter streamwriter = new StreamWriter(fs))
{
}
}
catch (Exception)
{
throw;
}
}
}
Agora, usando o método WriteLine()
do objeto streamwriter
, conseguiremos escrever o conteúdo da variável json
no arquivo. Após o using
, vamos imprimir uma mensagem para avisar o usuário que o arquivo foi salvo, indicando o diretório de destino.:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
try
{
FileStream fs = new FileStream(@"c:\tmp\export\contas.json",
FileMode.Create);
using (StreamWriter streamwriter = new StreamWriter(fs))
{
streamwriter.WriteLine(json);
}
Console.WriteLine(@"Arquivo salvo em c:\tmp\export\");
Console.ReadKey();
}
catch (Exception)
{
throw;
}
}
}
A seguir, modificaremos o bloco catch
. Nele, vamos lançar um ByteBankException
, a classe de exceção do nosso projeto:
private void ExportarContas()
{
Console.Clear();
Console.WriteLine("===============================");
Console.WriteLine("=== EXPORTAR CONTAS ===");
Console.WriteLine("===============================");
Console.WriteLine("\n");
if (_listaDeContas.Count <= 0)
{
Console.WriteLine("... Não existe dados para exportação...");
Console.ReadKey();
}
else
{
string json = JsonConvert.SerializeObject(_listaDeContas,
Formatting.Indented);
try
{
FileStream fs = new FileStream(@"c:\tmp\export\contas.json",
FileMode.Create);
using (StreamWriter streamwriter = new StreamWriter(fs))
{
streamwriter.WriteLine(json);
}
Console.WriteLine(@"Arquivo salvo em c:\tmp\export\");
Console.ReadKey();
}
catch (Exception excecao)
{
throw new ByteBankException(excecao.Message);
Console.ReadKey();
}
}
}
Recapitulando: selecionamos uma lista de objetos, realizamos uma serialização no formato JSON indentado e armazenamos o resultado na variável json
. Depois, criamos um arquivo chamado contas.json
, escrevemos o conteúdo da variável json
nele e salvamos o arquivo.
Para testar, vamos executar o projeto. No menu da aplicação, pressionaremos "2" para checar as contas cadastradas. Temos as contas do Henrique (com final X), do Pedro (com final X) e da Marisa (com final W).
Voltando ao menu, pressionaremos "6" para exportar as contas. No console, teremos a seguinte mensagem:
Arquivo salvo em c:\tmp\export\
Vamos abrir o gerenciador de arquivos e navegar até "c:\tmp\export", onde teremos o arquivo contas.json
! Clicaremos sobre ele com o botão direito do mouse e selecionaremos "Abrir com > Bloco de Notas". Seu conteúdo é o seguinte:
[
{
"Titular": {
"Cpf": "11111",
"Nome": "Henrique",
"Profissao": null
},
"Nome_Agencia": null,
"Numero_agencia": 95,
"Conta": "123456-X",
"Saldo": 100.0
},
{
"Titular": {
"Cpf": "22222",
"Nome": "Pedro",
"Profissao": null
},
"Nome_Agencia": null,
"Numero_agencia": 95,
"Conta": "951258-X",
"Saldo": 200.0
},
{
"Titular": {
"Cpf": "33333",
"Nome": "Marisa",
"Profissao": null
},
"Nome_Agencia": null,
"Numero_agencia": 94,
"Conta": "987321-W",
"Saldo": 60.0
}
]
Assim, temos a lista de contas salva em um arquivo no formato JSON, que podemos enviar para o Banco Central e atender à demanda do Bytebank.
Na sequência, continuaremos evoluindo nossa aplicação, entendendo mais sobre bibliotecas e como trabalhar com elas. Estudaremos o nível de visibilidade e como aplicar esse conceito no contexto de bibliotecas de classes.
O curso C#: criando e distribuindo bibliotecas em .NET possui 76 minutos de vídeos, em um total de 38 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.