TransWikia.com

Propriedade definida no construtor só retorna valor zero

Stack Overflow em Português Asked by EdeiltonSO on November 8, 2021

Criei uma Web API em C# que me retorna uma lista de produtos em JSON. Entretanto, a propriedade PrecoVenda sempre é retornada com o valor zero e notei que isso ocorre pois no construtor da classe Produto, o PrecoCusto também permanece em zero durante a execução do programa, como é possível ver na imagem abaixo.

PrecoCusto = 0

  • Se eu tenho os valores definidos na ListaProdutos.cs (nas propriedades PrecoCusto), o valor não deveria estar sendo captado no código acima?

  • Como isso poderia ser solucionado?

Segue o código:

ProdutosController.cs:

using System.Collections.Generic;
using System.Web.Http;
using WebAPI_0527.Models;
using WebAPI_0527.Dados;

namespace WebAPI_0527.Controllers
{
    public class ProdutosController : ApiController
    {
        [HttpGet]
        public List<Produto> GetProdutos()
        {
            return ListaProdutos.GetList();
        }
    }
}

ListaProdutos.cs

using System.Collections.Generic;
using WebAPI_0527.Models;

namespace WebAPI_0527.Dados
{
    public class ListaProdutos
    {
        public static List<Produto> GetList()
        {
            List<Produto> listaProdutos = new List<Produto>()
            {
                new Produto() { Id = 1, Nome = "Arroz", PrecoCusto = 12, Unidade = Produto.TipoDeUnidade.Kg.ToString(), Quantidade = 9 },
                new Produto() { Id = 2, Nome = "Leite", PrecoCusto = 5, Unidade = Produto.TipoDeUnidade.Litro.ToString(), Quantidade = 6 }
            };

            return listaProdutos;
        }
    }
}

Produto.cs

namespace WebAPI_0527.Models
{
    public class Produto
    {
        public int Id { get; set; }
        public string Nome { get; set; }
        public string Unidade { get; set; }
        public double Quantidade { get; set; }
        public double PrecoCusto { get; set; }
        public double PrecoVenda { get; set; }

        public Produto()
        {
            PrecoVenda = PrecoCusto + PrecoCusto / 3;
        }

        public enum TipoDeUnidade
        {
            Unidade,
            Litro,
            Balde,
            Par,
            Kg
        }
    }
}

3 Answers

Tem duas maneiras de resolver isto. A primeira é por pra funcionar. É um pequeno detalhe que está errado. A segunda, e é esta que vou mostrar, é aprendendo como realmente se resolve esse problema. Eu resolveria mais ou menos assim (tem como melhorar mais):

using static System.Console;
using System.Collections.Generic;

public class Program {
    public static void Main() {
        var listaProdutos = ListaProdutos.GetList();
        foreach (var produto in listaProdutos) WriteLine($"{produto.Nome} -> {produto.PrecoVenda:C}");
    }
}

public class ListaProdutos {
    public static List<Produto> GetList() => new List<Produto>() {
            new Produto(id : 1, nome : "Arroz", precoCusto : 12, unidade : Produto.TipoDeUnidade.Kg, quantidade : 9),
            new Produto(2, "Leite", Produto.TipoDeUnidade.Litro, 5, 6)
        };
}

public class Produto {
    public int Id { get; }
    public string Nome { get; set; }
    public TipoDeUnidade Unidade { get; set; }
    public decimal Quantidade { get; }
    public decimal PrecoCusto { get; set; }
    public decimal PrecoVenda { get => PrecoCusto * (4M / 3M); }
    
    public Produto(int id, string nome, TipoDeUnidade unidade, decimal quantidade, decimal precoCusto) {
        Id = id;
        Nome = nome;
        Unidade = unidade;
        Quantidade = quantidade;
        PrecoCusto = precoCusto;
    }
    
    public enum TipoDeUnidade { Unidade, Litro, Balde, Par, Kg }
}

Veja funcionando no ideone. E no repl.it. Também coloquei no GitHub para referência futura.

Alguns erros:

  • Um objeto deve ser construído em estado válido, em grande parte dos casos não se deve ter um construtor default, esse sem parâmetros, você deve ter um construtor que receba todos os dados mínimos para que o objeto esteja em estado válido. Veja Para que serve um construtor?. Foi o que eu fiz.
  • O Id costuma ser uma propriedade imutável, então não tem porque ter um set.
  • Deixei o nome e a unidade poder mudar, mas tenho dúvidas se deveria, esse é o problema de exemplos artificiais ou sem definição clara.
  • A Unidade não deve ser string e sim o tipo da própria enumeração. Mesmo que precise disto para colocar em banco de dados ou apresentar visualmente deveria ter outras formas de fazer isto. Para o banco de dados seria melhor fazer um cast na própria enumeração e ter uma propriedade para pegar o nome da unidade quando precisar do nome ou pegar o item da enumeração e aplicar o ToString() quando precisa.
  • Quando trabalhamos com valores monetários o que desejamos exatidão o tipo correto é o decimal e não o double que tem problemas de arredondamento.
  • A propriedade PrecoDeVenda me parece que é o que chamamos de virtual, ou seja ela sempre pega um outro valor e retorna,então ela não precisa ter estado. Caso precise ter um estado, porque nem sempre ela deve ser mudado de acordo com o custo ou pode ter um valor personalizado, aí precisa pensar em outra lógica. Não posso falar nada porque não sei a necessidade real.
  • Aproveitei para tornar o código mais moderno, legível na minha concepção, e usando a matemática de forma mais otimizada e inteligente.
  • Note que a quantidade ficou imutável, porque não acho que ela deveria ser mudada diretamente. Na verdade é comum em orientação a objeto não ter propriedades sendo modificadas diretamente. É mais comum ter um método que faz uma operação específica que tem como efeito colateral a mudança de estado interno. Tem casos que a mudança da propriedade é adequado, mas neste caso acho que um método que estabeleça uma venda ou compra ou outra operação de entrada e saída que deveria ser usada, aí talvez nem deveria estar no construtor, ou deveria estar de uma forma diferente.

Answered by Maniero on November 8, 2021

Além da forma que o @VirgilioNovic demonstrou, existe outra: a de passagem do preço de custo por construtor com parâmetro,

public Produto(double precoCusto)
{
    PrecoCusto = precoCusto;
    PrecoVenda = PrecoCusto * (1d + (1d / 3));
}

e daí, para usar o novo construtor, em ListaProdutos.GetList(), ficaria assim:

List<Produto> listaProdutos = new List<Produto>()
{
    new Produto(12.00) { Id = 1, Nome = "Arroz", /*PrecoCusto = 12,*/ ... },
    new Produto(5.00)  { Id = 2, Nome = "Leite", /*PrecoCusto = 5,*/ ... },
};

Isto caso PrecoVenda nem sempre seja exatamente igual a PrecoCusto + PrecoCusto / 3. Nunca se sabe quando o dono da empresa quer aumentar sua margem de lucro, não é mesmo? :P

Answered by Marcelo Shiniti Uchimura on November 8, 2021

Se eu tenho os valores definidos na ListaProdutos.cs (nas propriedades PrecoCusto), o valor não deveria estar sendo captado no código acima?

A resposta é não mediante ao seu código:

new Produto() { 
    Id = 1, 
    Nome = "Arroz", 
    PrecoCusto = 12, 
    Unidade = Produto.TipoDeUnidade.Kg.ToString(), 
    Quantidade = 9 
}

porque primeiramente, é instanciado a classe Produto e quando passe pelo construtor a propriedade ainda é o seu valor padrão que é 0 e quando entra na chaves começa a passagem de valores para essa instância da classe Produto.

Isso é importante você saber, que primeiramente há a criação da instância e depois a passagem de valor, claro que pode ser criado um construtor com paramentos e fazer o calculo no construtor, mas, eu acho mais lógica quando o valor é um calculo ser feito como no exemplo abaixo:

Como isso poderia ser solucionado?

Como o valor é calculado se pode colocar diretamente na classe da seguinte forma:

public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public string Unidade { get; set; }
    public double Quantidade { get; set; }
    public double PrecoCusto { get; set; }      
    public double PrecoVenda
    {
        get 
        {
            return (PrecoCusto + PrecoCusto) / 3;
        }
    }

    public Produto()
    {       
    }

    public enum TipoDeUnidade
    {
        Unidade,
        Litro,
        Balde,
        Par,
        Kg
    }
}

Confira no exemplo OnLine

Answered by novic on November 8, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP