Property set in constructor only returns zero value

2

I created a Web API in C # that returns me a list of products in JSON. However, the PrecoVenda property is always returned with a value of zero and I noticed that this occurs because in the constructor of the Produto class, PrecoCusto also stays at zero during program execution, as you can see in the image below.

  

  • IfIhavethevaluessetinListaProdutos.cs(inpropertiesPrecoCusto),shouldnotthevaluebefetchedintheabovecode?

  • Howcouldthisbesolved?

Followthecode:

ProductsController.cs:

usingSystem.Collections.Generic;usingSystem.Web.Http;usingWebAPI_0527.Models;usingWebAPI_0527.Dados;namespaceWebAPI_0527.Controllers{publicclassProdutosController:ApiController{[HttpGet]publicList<Produto>GetProdutos(){returnListaProdutos.GetList();}}}

ProductProducts.cs

usingSystem.Collections.Generic;usingWebAPI_0527.Models;namespaceWebAPI_0527.Dados{publicclassListaProdutos{publicstaticList<Produto>GetList(){List<Produto>listaProdutos=newList<Produto>(){newProduto(){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;
        }
    }
}

Product.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
        }
    }
}
    
asked by anonymous 28.05.2018 / 01:00

3 answers

4

There are two ways to solve this. The first is to work. It's a little detail that is wrong. The second, and this is what I will show, is learning how to really solve this problem. I'd sort it out like this (have to improve it more:

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 }
}

Some errors:

  • An object must be built in a valid state, in most cases you should not have a default constructor, this without parameters, you must have a constructor that receives all the minimum data so that the object is in valid state. See What is a builder for? . That's what I did.
  • Id is usually an immutable property, so you do not have to set .
  • I let the name and drive be able to change, but I have doubts if it should, that's the problem of artificial examples or with no clear definition.
  • The Unidade should not be string but the type of the enumeration itself. Even if you need this to be placed in a database or presented visually, you should have other ways of doing this. For the database it would be better to do a cast in the enumeration itself and have a property to get the name of the unit when it needs the name or get the enumeration item and apply the% / li>
  • When working with monetary values we want accuracy The correct type is ToString() and not decimal that has rounding problems.
  • The double property seems to me to be what we call virtual, that is, it always takes another value and returns, so it does not have to be. If you need to have a status, because it does not always have to be changed according to the cost or you can have a custom value, then you need to think of another logic. I can not say anything because I do not know the real need.
  • I made the code more modern, readable in my design, and use math more optimally and intelligently.
  • Note that the quantity has remained unchanged, because I do not think it should be changed directly. In fact it is common in object orientation not to have properties being modified directly. It is more common to have a method that does a specific operation that has as a side effect the internal state change. There are cases where the change of ownership is appropriate, but in this case I think that a method that establishes a sale or purchase or other input and output operation that should be used, there maybe should not even be in the constructor, or it should be in a different way .
28.05.2018 / 01:58
2
  

If I have the values defined in the ProductsList.cs (in the PreCost properties), should the value not be fetched in the above code?

The answer is not through your code:

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

First, the Produto is instantiated, and when it passes the constructor, the property is still its default value that is 0, and when it enters the keys it starts passing values to that instance of the Produto class.

This is important to know, that first there is the creation of the instance and then the value pass, of course you can create a constructor with paramentos and do the calculation in the constructor, but, I think more logical when the value is one I calculate it to be done as in the example below:

  

How could this be solved?

How the value is calculated can be placed directly into the class as follows:

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
    }
}

Check out the OnLine example

    
28.05.2018 / 01:15
1

In addition to the way that @VirgilioNovic has demonstrated, there is another way of passing the cost price by constructor with parameter ,

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

Then, to use the new constructor, in ListaProdutos.GetList() , would look like this:

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,*/ ... },
};

This case PrecoVenda is not always exactly equal to PrecoCusto + PrecoCusto / 3 . You never know when the owner of the company wants to increase his profit margin, right? : P

    
28.05.2018 / 01:24