C#
- Modelos de código para cenários complexos
![]() |
Hoje vou apresentar três trechos de códigos que podemos usar em cenários mais complexos. |
No dia a dia sempre vai surgir a necessidade de aplicar um código para resolver um cenário mais complexo, e muitas vezes esse cenário customa se repetir.
Desta forma vou mostrar três trechos de códigos que você pode usar para aplicar nestes cenários.
Cenário 1 - Multithreading com Paralelismo de tarefas (Task)
O multithreading pode melhorar muito o desempenho dos aplicativos. Utilizando a classe Task do namespace System.Threading.Tasks, você pode obter uma execução paralela eficiente.
A classe Task no namespace System.Threading.Tasks é uma parte importante da API de Tarefas usada para criar e gerenciar tarefas assíncronas. Ela é frequentemente utilizada para obter execuções paralelas eficientes em cenários de programação multithreading.
Aqui está um exemplo de uso de tarefas para processamento paralelo:
1- Modelo
Task<int>
task1 = Task.Run(() => CalcularValor()); Task<int> task2 = Task.Run(() => CalcularOutroValor()); await Task.WhenAll(task1, task2);int resultado1 = task1.Result;int resultado2 = task2.Result; Console.WriteLine( $"Resultado 1: {resultado1}, Resultado 2: {resultado2}");static int CalcularValor(){ /* Implementação */ } static int CalcularOutroValor(){ /* Implementação */ } |
await Task.WhenAll(task1, task2);
O método WhenAll da classe Task aceita uma coleção de tarefas (ou parâmetros separados por vírgula) e retorna uma nova tarefa que representa a conclusão de todas as tarefas fornecidas.
Este código faz com que o programa aguarde a conclusão das tarefas task1 e task2 antes de prosseguir para as próximas instruções. Isso é importante quando você deseja garantir que todas as tarefas tenham terminado antes de prosseguir com o processamento dos resultados ou tomar outras ações que dependem do resultado dessas tarefas.
2- Implementação
Task<long> task1 = Task.Run(() => CalcularFibonacci(10));
Task<long> task2 = Task.Run(() => CalcularFatorial(5));
await Task.WhenAll(task1, task2);
long resultado1 = task1.Result;
long resultado2 = task2.Result;
Console.WriteLine($"Resultado Fibonacci: {resultado1}, Resultado Fatorial: {resultado2}");
static long CalcularFibonacci(int n)
{
if (n <= 0)
return 0;
if (n == 1)
return 1;
long a = 0;
long b = 1;
long result = 0;
for (int i = 2; i <= n; i++)
{
result = a + b;
a = b;
b = result;
}
return result;
}
static long CalcularFatorial(int n)
{
if (n == 0)
return 1;
if (n < 0)
throw new ArgumentException("O fatorial não está definido para números negativos.");
long resultado = 1;
for (int i = 1; i <= n; i++)
{
resultado *= i;
}
return resultado;
}
|
Neste exemplo, CalcularFibonacci calcula o n-ésimo número de Fibonacci e CalcularFatorial calcula o fatorial de um número. Ambos são tarefas práticas que podem ser executadas em paralelo usando a classe Task. O resultado dessas tarefas é esperado após o await com Task.WhenAll, e os valores calculados são impressos na saída.
Cenário 2 - Acesso a arquivos de forma Assíncrona
Tratar com operações assíncronas de arquivos é essencial para aplicativos responsivos. As palavras-chave async e await simplificam a programação assíncrona e os recursos StreamReader, ReadFileAsync() e ReadToEndAsync() permite fazer o acesso assíncrono.
1- Modelo
string
caminhoArquivo =
"data.txt"; using (StreamReader reader = new StreamReader(caminhoArquivo)){ string conteudo = await reader.ReadToEndAsync(); Console.WriteLine(conteudo); } |
StreamReader é uma
classe no namespace System.IO que é usada para leitura de fluxos de caracteres
de forma eficiente, principalmente em operações de leitura de arquivos de texto.
Ele oferece métodos para ler dados de um Stream de forma assíncrona ou síncrona.
Alguns de seus métodos comuns incluem:
- Read(): Lê o próximo caractere a partir do fluxo.
- ReadLine(): Lê a próxima linha de texto do fluxo.
- ReadToEnd(): Lê o restante do fluxo até o final.
StreamReader é especialmente útil quando você deseja ler um arquivo de texto de
forma eficiente, pois ele faz buffering automático, minimizando as operações de
leitura no disco.
ReadFileAsync é um método assíncrono personalizado que lê o conteúdo de um arquivo de forma assíncrona usando StreamReader. Ele aceita um caminho de arquivo como argumento e retorna uma tarefa que representa a operação de leitura assíncrona.
ReadToEndAsync é um método da classe StreamReader que lê o restante do fluxo de caracteres até o final de forma assíncrona. Ele retorna uma tarefa que representa a operação de leitura assíncrona. O uso do await com ReadToEndAsync permite que a leitura do arquivo seja realizada de forma assíncrona, evitando o bloqueio da thread principal.
2- Implementação
string
caminhoArquivo =
"exemplo.txt";
// O caminho
para o arquivo try { // Ler o conteúdo do arquivo de forma assíncrona string conteudo = await ReadFileAsync(caminhoArquivo); // Processar o conteúdo lido, por exemplo, exibir na tela Console.WriteLine("Conteúdo do arquivo:"); Console.WriteLine(conteudo); } catch (Exception ex) { Console.WriteLine($"Ocorreu um erro ao ler o arquivo: {ex.Message}"); } Console.ReadKey(); static async Task<string> ReadFileAsync(string caminhoArquivo){ using (StreamReader reader = new StreamReader(caminhoArquivo)) { return await reader.ReadToEndAsync(); } } |
Entendendo o código:
Cenário 3 - Tratamento de exceções customizadas
A criação de exceções personalizadas permite lidar com casos de erros específicos com mais eficiência. Além disso as exceções personalizadas são importantes por vários motivos, incluindo:
1- Modelo
try { int result = RealizarOperacaoComplexa(); if (result < 0) { throw new CustomException("Um resultado negativo não é permitido."); } } catch (CustomException ex) { Console.WriteLine($"Exceção Customizada: {ex.Message}"); } static int RealizarOperacaoComplexa(){ /* Implementação */ } class CustomException : Exception{ public CustomException(string message) : base(message) { } } |
A seguir temos um exemplo de definição e uso de uma exceção personalizada onde criaremos uma classe de exceção personalizada chamada CustomDataException, que incluirá informações adicionais, como a hora em que ocorreu a exceção e os dados relacionados ao erro.
Este é um exemplo mais complexo para ilustrar como você pode criar exceções personalizadas mais ricas em informações:
using System;
using System.Runtime.Serialization;
[Serializable]
class CustomDataException : Exception
{
public DateTime Timestamp { get; }
public string ErrorData { get; }
public CustomDataException(string message, string errorData) : base(message)
{
Timestamp = DateTime.Now;
ErrorData = errorData;
}
public CustomDataException(string message, string errorData, Exception innerException)
: base(message, innerException)
{
Timestamp = DateTime.Now;
ErrorData = errorData;
}
protected CustomDataException(SerializationInfo info, StreamingContext context) : base(info, context)
{
Timestamp = info.GetDateTime("Timestamp");
ErrorData = info.GetString("ErrorData");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("Timestamp", Timestamp);
info.AddValue("ErrorData", ErrorData);
}
}
class Program
{
static void Main(string[] args)
{
try
{
SimularOperacaoComErro();
}
catch (CustomDataException ex)
{
Console.WriteLine($"Custom Data Exception: {ex.Message}");
Console.WriteLine($"Timestamp: {ex.Timestamp}");
Console.WriteLine($"Error Data: {ex.ErrorData}");
}
}
static void SimularOperacaoComErro()
{
try
{
// Simulação de uma operação com erro
throw new CustomDataException("Ocorreu um erro durante a operação.", "Dados de erro específicos");
}
catch (Exception ex)
{
// Captura e relança a exceção
throw new CustomDataException("Erro na operação interna.", "Dados internos de erro", ex);
}
}
}
|
Entendendo o código:
Este exemplo ilustra como criar uma exceção personalizada que pode conter informações adicionais para facilitar a depuração e o tratamento de erros complexos.
Pegue o código aqui:
CodigosCenarios.zip
E estamos conversados...
"Porque o amor ao dinheiro é a raiz de todos os males; e nessa cobiça alguns se
desviaram da fé, e se traspassaram a si mesmos com muitas dores"
1 Timóteo 6:10
Referências:
.NET MAUI - Lançamento da Release Candidate