Aprenda comigo: Documentando meu aprendizado em C# - Exceções
QUEM SOU EU?
Eu me chamo Marcos Vinicius, tenho 20 anos e estou estudando para me tornar um dev backend utilizando C#. Uma vez eu ouvi que quem ensina aprende 2X. Então, é por isso que estou aqui!
Quero deixar bem claro que não sou nenhum especialista em C#, sou apenas um estudante que irá compartilhar conceitos aprendidos ao longo da minha jornada até me tornar um dev.
Escolhi escrever aqui no TabNews pois creio que posso ajduar outros estudantes e praticar o que aprendi. Eu já escrevi outras vezes aqui, mas todas as vezes foram pedindo ajuda. Então senti que estava em dívida e tinha que fazer algo para contribuir na comunidade e esta foi a forma que encontrei! Desde já quero dizer que outros devs com mais experiencia poderá ficar a vontade para me corrigir ou adicionar mais alguma informação que esqueci.
Outro motivo para eu escrever em locais públcios é fazer networking com outros devs. Abaixo deixarei minhas redes socias. Fique a vontade para me adicionar e trocar ideia:
Meu instagram
Meu Linkedin, que preciso arrumar kkk
Meu discord: marcosvinicius2448
HOJE VAMOS FALAR SOBRE EXCEÇÕES
Primeiramente irei fazer uma breve introduçãom sobre o que é uma exceção em C# e provavelmente o conceito é o mesmo para a maioria das linguagens.
O QUE É UMA EXECEÇÃO?
Uma exceção é quando nosso programa, ao ser execetudo, acontece algo inesperado ou age de forma não esperada, interrompendo o fluxo do programa. Por exemplo, quando é criado um programa para ler um arquivo, porém este arquivo não existe, como o programa não encontrou o arquivo, ele não conseguirá concluir com sucesso seu objeito e irá dispará uma exceção. Neste caso seria algo como "FIleNotFound". É aqui que entra os blocos try/catch e o tratamento de exceções.
TRY/CATCH E TRATAMENTO DE EXCEÇÕES
O código a seguir é básico e é somente para exemplificar uma exceção de arquivo não encontrado. O código basicamente lê as linhas de um arquivo.txt. Porém, propositalmente eu errei o nome do arquivo ao tentar acessar via ReadAllLines. Veja o exemplo a seguir:
string[] linhas = File.ReadAllLines("arquivos/leitura01.txt");
foreach (string linha in linhas)
{
Console.WriteLine(linha);
}
Está é a exceção disparada no terminal:
Unhandled exception. System.IO.FileNotFoundException: Could not find file '/home/marcos/estudos/dotnet/curso_dio/explorando_c#/ex01/book/arquivos/leitura01.txt'.
File name: '/home/marcos/estudos/dotnet/curso_dio/explorando_c#/ex01/book/arquivos/leitura01.txt'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Func`4 createOpenException)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Func`4 createOpenException)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
at System.IO.File.ReadAllLines(String path, Encoding encoding)
at Program.<Main>$(String[] args) in /home/marcos/estudos/dotnet/curso_dio/explorando_c#/ex01/book/Program.cs:li
Veja que é uma mensagem enorme e pode ser até difícil de entender. Neste caso o programa é imediatamente interrompido porque a exceção não tem tratamento.
TRATANDO A EXCEÇÃO COM TRY E CATCH
Os dois nomes são bem intuitivos, mas vamos começar pelo Try, que significa "tentar", ou seja, como o próprio nome já sugere, irá tentar fazer algo. Você adiciona uma instrução em seu corpo e com isso, um alerta é soltado para o compilador, algo como "executa este bloco de código aqui, mas como cuidado". Abaixo um exemplo:
try
{
string[] linhas = File.ReadAllLines("arquivos/leitura01.txt");
foreach (string linha in linhas)
{
Console.WriteLine(linha);
}
}
Neste exemplo, o programa irá tentar ler e exibir no terminal as linhas do arquivo.txt. Se por acaso alguma exceção for disparada, o bloco catch é acionado. Abaixo um exemplo com o bloco catch:
try
{
string[] linhas = File.ReadAllLines("arquivos/leitura01.txt");
foreach (string linha in linhas)
{
Console.WriteLine(linha);
}
} catch(FileNotFoundException ex)
{
Console.WriteLine($"Arquivo não encontrado {ex.Message}");
}
O catch, que significa "pegar". Irá ficar responsável por pegar a exceção e trata-la, ou seja, executar outro bloco de código caso a exceção seja disparada. No exemplo acima é uma simples mensagem no terminal, mas poderia até ser um disparo de email pelo departamento responsável pelos arquivos, por exemplo.
EXPLICANDO O CATCH:
No catch é passado como paramentro a exceção que ele irá monitorar, que neste caso é a de FileNotFound, ou arquivo não encontrado e a seguir é o nome da variavel que irá guardar aquela exceção, que neste caso foi a "ex". Já no Console.WriteLine o ex.Message é para exibir a mensagem daquela exceção. No terminal irá aparecer a seguinte mensagem:
Arquivo não encontrado Could not find file '/home/marcos/estudos/dotnet/curso_dio/explorando_c#/ex01/book/arquivos/leitura01.txt'.
Poderia ser exibido no console somente o ex.Message que já seria entendido. Assim é mais pratico, não é mesmo? Em vez de ter todas aquelas mensagens do primeiro terminal. é exibido so uma e é mais facil de saber onde esta o problema em seu programa.
OBS: Semppre colocar as exceções espeficicas primeiro no catch e abaixo as exceções genericas, como no exemplo a seguir:
try
{
string[] linhas = File.ReadAllLines("arquivos/leitura01.txt");
foreach (string linha in linhas)
{
Console.WriteLine(linha);
}
} catch(FileNotFoundException ex)
{
Console.WriteLine($"Arquivo não encontrado {ex.Message}");
}
catch(Exception ex)
{
Console.WriteLine($"Erro genérico: {ex.Message}");
}
As exceções espeficas como o próprio nome sugere, são exceções de algo especifico Por exemplo, o FileNotFound. Isto é uma execeção especifica de arquivos não encontrados. Já as exceções genericas são de algo não especifico, como o proprio nome também sugere!
FINALMENTE CHEGAMOS AO BLOCO FINALLY:
Outro nome muito intuitivo também. Ele fica abaixo de todos os catch, como o exemplo abaixo:
try
{
string[] linhas = File.ReadAllLines("arquivos/leitura01.txt");
foreach (string linha in linhas)
{
Console.WriteLine(linha);
}
} catch(FileNotFoundException ex)
{
Console.WriteLine($"Arquivo não encontrado {ex.Message}");
}
catch(Exception ex)
{
Console.WriteLine($"Erro genérico: {ex.Message}");
}
finally
{
Console.WriteLine("Irá executar independente de erros");
}
O finally irá executar o que estiver em seu corpo independente de disparos de exceções ou não.
Um caso de uso dele é quando se tem uma conexão com um banco de dados para consumir um certo dado. Se voce consome este dado e não fecha a conexão, seu programa ficará consumindo memória, o que não é legal. É neste caso que entra o finallt, onde mesmo a consulta sendo bem-sucedida ou não, pode ser escrito um bloco de código onde a conexão com o banco de dados é encerrada após cada consulta.
Concluindo...
Então, muito obrigado a voce que leu ate que. Espero ter ajudado de alguma forma. Fique a vontade para comentar qualquer critica construtiva ou adicionar informações que eu esqueci.
Vou deixar abaixo o link sobre exceção direto da documentação, para quem quiser se aprofundar mais no tema: