Desafio C#

Relatório de vendas com execução adiada

Enunciado

Crie um programa que demonstre a execução adiada do LINQ. Dada uma lista de vendas, monte uma consulta que filtre vendas acima de um valor mínimo e projete o nome do vendedor e o valor. Antes de iterar, adicione uma nova venda que atenda ao filtro. Exiba o resultado e comprove que a nova venda aparece. Em seguida, use GroupBy para agrupar por vendedor e mostrar o total, ordenado pelo total decrescente.

Requisitos

  • Monte a consulta LINQ sem executá-la imediatamente (sem ToList antes da modificação).
  • Adicione uma nova venda à lista original após definir a consulta.
  • Exiba os resultados da consulta incluindo a nova venda.
  • Use GroupBy para agrupar por vendedor e exibir total ordenado decrescentemente.

Código inicial

using System;
using System.Linq;
using System.Collections.Generic;

class Venda
{
    public string Vendedor { get; set; }
    public decimal Valor { get; set; }
}

class Program
{
    static void Main()
    {
        var vendas = new List<Venda>
        {
            new Venda { Vendedor = "Ana", Valor = 100 },
            new Venda { Vendedor = "Bruno", Valor = 200 },
            new Venda { Vendedor = "Ana", Valor = 150 },
            new Venda { Vendedor = "Carlos", Valor = 300 }
        };

        // 1. Crie a consulta para vendas > 120 sem executar
        // 2. Adicione uma nova venda (ex.: "Diana", 250)
        // 3. Exiba os resultados da consulta
        // 4. Agrupe por vendedor e exiba total ordenado decrescentemente
    }
}

Saída esperada

Vendas acima de R$ 120,00:
Bruno: R$ 200,00
Ana: R$ 150,00
Carlos: R$ 300,00
Diana: R$ 250,00

Total por vendedor (decrescente):
Carlos: R$ 300,00
Diana: R$ 250,00
Bruno: R$ 200,00
Ana: R$ 250,00
Ver dica

A consulta Where é adiada; se você não chamar ToList() antes de adicionar a venda, o novo item será incluído ao iterar. Para o agrupamento, use GroupBy e Sum.

Mostrar solução
using System;
using System.Linq;
using System.Collections.Generic;

class Venda
{
    public string Vendedor { get; set; }
    public decimal Valor { get; set; }
}

class Program
{
    static void Main()
    {
        var vendas = new List<Venda>
        {
            new Venda { Vendedor = "Ana", Valor = 100 },
            new Venda { Vendedor = "Bruno", Valor = 200 },
            new Venda { Vendedor = "Ana", Valor = 150 },
            new Venda { Vendedor = "Carlos", Valor = 300 }
        };

        // 1. Consulta adiada: ainda não executa
        var consulta = vendas
            .Where(v => v.Valor > 120)
            .Select(v => $"{v.Vendedor}: R$ {v.Valor:F2}");

        // 2. Adiciona nova venda após a definição da consulta
        vendas.Add(new Venda { Vendedor = "Diana", Valor = 250 });

        // 3. Executa a consulta (inclui Diana)
        Console.WriteLine("Vendas acima de R$ 120,00:");
        foreach (var item in consulta)
            Console.WriteLine(item);

        // 4. Agrupamento por vendedor com total
        var totais = vendas
            .GroupBy(v => v.Vendedor)
            .Select(g => new { Vendedor = g.Key, Total = g.Sum(v => v.Valor) })
            .OrderByDescending(x => x.Total);

        Console.WriteLine("\nTotal por vendedor (decrescente):");
        foreach (var t in totais)
            Console.WriteLine($"{t.Vendedor}: R$ {t.Total:F2}");
    }
}

Passo a passo

  1. Criamos a lista de vendas com quatro registros.
  2. Definimos consulta usando Where e Select, mas sem chamar ToList — a execução fica adiada.
  3. Adicionamos uma nova venda (Diana, 250) à lista original.
  4. Ao iterar com foreach, a consulta é executada e inclui a nova venda, comprovando a execução adiada.
  5. Para o agrupamento, usamos GroupBy por vendedor, projetamos com Select e somamos os valores.
  6. Ordenamos os totais com OrderByDescending e exibimos.

Por que funciona

A execução adiada é possível porque os operadores LINQ retornam um IEnumerable<T> que armazena a lógica da consulta, não os dados. Quando o foreach chama GetEnumerator(), a consulta é avaliada sobre a fonte no estado atual — por isso a venda adicionada depois aparece. Já GroupBy também é adiado, mas ao iterar sobre os grupos, todos os dados são processados.

Erros comuns

  • Chamar ToList() antes de adicionar a venda: a consulta seria materializada e a nova venda não apareceria.
  • Modificar a lista durante a iteração (ex.: adicionar dentro do foreach): lança InvalidOperationException.
  • Esquecer using System.Linq;: os métodos de extensão não são reconhecidos.

Outra forma de resolver

Usar sintaxe de consulta para o agrupamento:

var totais = from v in vendas
             group v by v.Vendedor into g
             orderby g.Sum(x => x.Valor) descending
             select new { Vendedor = g.Key, Total = g.Sum(x => x.Valor) };

É preferível quando a consulta tem muitas cláusulas e fica mais próxima de SQL.

Saída esperada

Vendas acima de R$ 120,00:
Bruno: R$ 200,00
Ana: R$ 150,00
Carlos: R$ 300,00
Diana: R$ 250,00

Total por vendedor (decrescente):
Carlos: R$ 300,00
Diana: R$ 250,00
Bruno: R$ 200,00
Ana: R$ 250,00