Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Dúvida com GET e SET

Quando usamos a sintaxe

public double Saldo { get; set; }

Se formos utilizar o campo Saldo em métodos de regra de negócio, como por exemplo no método Sacar(double valor), a implementação interna do método será:

        public bool Sacar(double valor)
        {
            if (Saldo <= valor)
            {
                return false;
            }
            Saldo -= valor;
            return true;
        }

Isso está correto? Eu só devo criar um atributo private com underscore( private double _saldo) quando eu for manipular eles dentro do GET/SET ou é necessário criar sempre que eu for manipular esse atributo em qualquer método que utilize o campo, como no Sacar(double valor) por exemplo.

No caso, o código acima funciona normalmente, porém fiquei na dúvida desse campo com o underscore (_)... por que eu sei que ele é criado pelo compilador quando usamos a sintaxe (public double Saldo { get; set; }).

5 respostas

Oi Leonardo, tudo bem?

Boa pergunta. O primeiro exemplo declara Saldo como propriedade automaticamente implementada (autoproperty) e, como você bem lembrou, um campo privado saldo é criado automaticamente pelo compilador. Como esse campo não está visível, você é obrigado a usar os acessadores get e set da propriedade dentro do método Sacar().

Vamos dar uma olhada na propriedade:

public double Saldo { get; set; }

O maior problema que vejo aqui nem é o uso ou não do campo com underscore no lugar da propriedade. Se você usar a propriedade no lugar do campo, a diferença vai ser imperceptível.

O problema mais sério aqui é que você está expondo a propriedade com o modificador public. Isso permite que um código externo à classe modifique diretamente o saldo da conta, o que é inaceitável, pois a classe precisa proteger esse valor.

No mínimo, você deveria esconder o acessador set, com private ou protected:

public double Saldo { get; private set; }

Dessa forma, somente a própria classe (ou uma subclasse poderia modificar o saldo).

Outro problema que vi foi o uso de um valor de retorno, caso o valor do saque seja maior que o saldo:

            if (Saldo <= valor)
            {
                return false;
            }

Esse tipo de código é uma herança da programação procedural (pré-OOP) e portanto considerado obsoleto. Você poderia substituir o "return false" por uma exceção, por exemplo:

            if (Saldo <= valor)
            {
                throw new SaldoInsuficienteException();
            }

Assim, em vez de tratar o valor de retorno no código cliente (o que pode não acontecer, por descuido de programação), uma exceção representa uma anormalidade na execução, e portanto obriga o desenvolvedor a capturar tratar o problema.

Note que estamos usando aqui uma classe customizada de exceção, SaldoInsuficienteException, que é para deixar bem claro o que aconteceu. Você pode também encapsular uma mensagem de erro bem descritiva dentro da classe de exceção.

Outro ponto que observei também é que a condição if (Saldo <= valor) não permite que o usuário saque todo o saldo. Talvez devesse, o que acha?

            if (Saldo < valor)
            {
                throw new SaldoInsuficienteException();
            }

Muito bem observado Marcelo a questão do saque não permitir o valor inteiro. Agradeço.

Então, eu ainda não cheguei no módulo que fala sobre Exceptions. Esse código foi desenvolvido durante a aula.

Eu só queria entender melhor mesmo de que forma que tenho que fazer. Eu conheço mais sobre o universo Java e lá declaramos todos os atributos como private e os acessamos através do get/set.

Acontece que no C#, podemos encurtar a declaração dos métodos get/set com a sintaxe:

public double Saldo { get; set; }

Com isso, declaramos uma propriedade Saldo com seus respectivos métodos de acesso e o compilador cria um atributo private double _saldo, correto?

A minha dúvida é:

Eu tenho que definir o atributo

private double _saldo;

todas as vezes que eu tiver uma lógica de set que não seja a de costume (somente atribuir o valor no this._saldo) ou também quando utilizamos aquele atributo em algum método (nesse caso no método Sacar(double valor)? Qual a melhor maneira de se fazer isso? Isso ficou um pouco confuso.

solução!

Oi Leonardo, acho que entendi sua dúvida

Se a sua lógica de set não faz nada além de setar o valor de this._saldo, você pode usar autoproperty: public double Saldo { get; private set; }. E não tem problema usar essa propriedade em outros métodos da classe, sem um campo auxiliar _saldo.

Se precisar, você pode expandir o setter e implementar a lógica adicional (aí você é obrigado a usar um campo auxiliar privado):

private decimal saldo;
public decimal Saldo
{ 
get { return saldo; }
private set 
{ 
    Log($"Saldo está sendo alterado de {saldo} para {value}");
    saldo = value;
}

Era exatamente isso que eu queria confirmar Marcelo. Muito obrigado.

Excelente, Leonardo, obrigado por participar do fórum!