Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
1
resposta

[Projeto] Faça como eu fiz: mais uma classe

Classe Program:

using ScreenSound_API.Filtros;
using ScreenSound_API.Modelo;
using System.Text.Json;

using (HttpClient cliente = new())
{
    var resposta = await cliente.GetStringAsync("https://guilhermeonrails.github.io/api-csharp-songs/songs.json");

    List<Musica> musicas = JsonSerializer.Deserialize<List<Musica>>(resposta)!;

    FiltroAnoLancamento.Artista(musicas, 2012);
    FiltroAnoLancamento.Musica(musicas, 2012);
    FiltroAnoLancamento.ArtistaEMusica(musicas, 2019);
}

Classe Musica:

using System.Text.Json.Serialization;

namespace ScreenSound_API.Modelo;

internal class Musica
{
    [JsonPropertyName("artist")]
    public string? Artista { get; set; }

    [JsonPropertyName("song")]
    public string? Nome { get; set; }

    [JsonPropertyName("year")]
    public string? AnoLancamentoString { get; set; }

    public int AnoLancamento
    {
        get
        {
            return AnoLancamentoString != null ? int.Parse(AnoLancamentoString) : 0;
        }
    }
}

Classe FiltroAnoLancamento:

using ScreenSound_API.Modelo;

namespace ScreenSound_API.Filtros;

internal class FiltroAnoLancamento
{
    public static void Artista(List<Musica> musicas, int anoLancamento)
    {
        var artistasQueLancaramMusicas = musicas
            .Where(m => m.AnoLancamento == anoLancamento)
            .OrderBy(m => m.Artista)
            .Select(m => m.Artista)
            .Distinct()
            .ToList();

        Console.WriteLine($"Artistas que lançaram musicas em {anoLancamento}:");

        foreach (var artista in artistasQueLancaramMusicas)
        {
            Console.WriteLine($"- {artista}");
        }
    }

    public static void Musica(List<Musica> musicas, int anoLancamento)
    {
        var musicasLancadas = musicas
            .Where(m => m.AnoLancamento == anoLancamento)
            .OrderBy(m => m.Nome)
            .Select(m => m.Nome)
            .Distinct()
            .ToList();

        Console.WriteLine($"Musicas lançaram em {anoLancamento}:");

        foreach (var musica in musicasLancadas)
        {
            Console.WriteLine($"- {musica}");
        }
    }

    public static void ArtistaEMusica(List<Musica> musicas, int anoLancamento)
    {
        var artistasQueLancaramMusicas = musicas
            .Where(m => m.AnoLancamento == anoLancamento)
            .OrderBy(m => m.Artista)
            .Select(m => m.Artista)
            .Distinct()
            .ToList();

        Console.WriteLine($"Artistas e musicas lançadas em {anoLancamento}:");

        foreach (var artista in artistasQueLancaramMusicas)
        {
            Console.WriteLine($"* {artista}");

            var musicasLancadas = MusicasPorArtista(musicas, artista!, anoLancamento);

            foreach (var musica in musicasLancadas)
            {
                Console.WriteLine($"  -> {musica}");
            }
        }
    }

    private static List<string> MusicasPorArtista(List<Musica> musicas, string artista, int anoLancamento)
    {
        var artistasQueLancaramMusicas = musicas
            .Where(m => m.Artista!.Equals(artista) && m.AnoLancamento == anoLancamento)
            .OrderBy(m => m.Nome)
            .Select(m => m.Nome)
            .Distinct()
            .ToList();

        return artistasQueLancaramMusicas!;
    }
}

Tentei explorar um pouco mais os filtros, onde criei um filtro para:

  • Artistas que tiveram musicas lançadas no ano X
  • Musicas que foram lançadas no ano X
  • Artistas e Musicas lançadas no ano X

Acredito que o método ArtistaEMusica da classe FiltroAnoLancamento ficou um pouco bagunçado, não sei se teria uma forma melhor de fazer, pois acabei repetindo um pouco de código.

Na classe Musica utilizei o comando int.Parse(AnoLancamentoString) mas verifiquei que também existe o comando Convert.ToInt32(AnoLancamentoString) qual a diferença dos 2 e quando se usa cada um?

1 resposta
solução!

Olá, Fabiano! Como vai?

Gostei bastante da forma como você explorou os filtros além do proposto na atividade. A separação da responsabilidade na classe FiltroAnoLancamento ficou organizada e demonstra uma boa prática ao utilizar LINQ para consultas específicas. Sobre o método ArtistaEMusica, sua percepção faz sentido, veja como ajustar: você poderia utilizar um GroupBy() para agrupar as músicas por artista e evitar repetir parte da lógica de busca dos artistas.

Sobre int.Parse() e Convert.ToInt32(), a principal diferença é que int.Parse() gera exceção quando recebe null ou um valor inválido, enquanto Convert.ToInt32() retorna 0 para null, mas também gera exceção para textos não numéricos. Como sua propriedade já verifica se o valor é diferente de null, o uso de int.Parse() ficou adequado.

Uma dica interessante para o futuro é utilizar int.TryParse() quando existir a possibilidade de receber dados inválidos da API, evitando exceções durante a execução. Veja este exemplo:


string anoString = "2012";

if (int.TryParse(anoString, out int ano))
{
Console.WriteLine(ano);
}

Nesse exemplo, o método tenta converter o texto para número e só executa o bloco quando a conversão for realizada com sucesso.

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!