As mudanças de Expression-bodied members no C# 7

Na versão 3.0 do C# surgiram as expressões lambda, como uma parte do LINQ. Na prática, elas não passam de funções anônimas, que dispensam a implementação no corpo da classe de operações simples, geralmente com apenas uma instrução.

Concebidas para simplificar e facilitar a codificação das aplicações, até a versão 5.0 do C#, elas eram utilizadas apenas dentro do corpo dos métodos de uma classe. Mas na versão 6.0 foi introduzido um novo recurso chamado Expression-bodied Members.

Em um passado não muito distante …

O Expression-bodied Members introduzido no C# 6.0 passou a permitir que expressões semelhantes às expressões lambdas fossem utilizadas para definir métodos ou propriedades somente leitura que contenham apenas uma instrução.

Por exemplo, vamos supor uma classe Pessoa que possua a estrutura abaixo:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get { return nome; }
        set { nome = value; }
    }

    public string Sobrenome
    {
        get { return sobrenome; }
        set { nome = value; }
    }

    public DateTime DataNascimento
    {
        get { return dataNascimento; }
        set { dataNascimento = value; }
    }

    public string NomeCompleto
    {
        get { return nome + " " + sobrenome; }
    }

    public int Idade()
    {
        return (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
    }
}

Com o expression-bodied properties, uma propriedade somente leitura:

public string NomeCompleto
{
    get { return nome + " " + sobrenome; }
}

Pode ser alterada para:

public string NomeCompleto => nome + " " + sobrenome;

E com o expression-bodied methods, o método Idade:

public int Idade()
{
    return (DateTime.Now.Year - dataNascimento.Year - 1) +
        (((DateTime.Now.Month > dataNascimento.Month) ||
        ((DateTime.Now.Month == dataNascimento.Month) && 
        (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Pode ser modificado para:

public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
                (((DateTime.Now.Month > dataNascimento.Month) ||
                ((DateTime.Now.Month == dataNascimento.Month) && 
                (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);

É importante frisar que em ambos os exemplos acima os blocos continham return, mas em um método sem isso:

public void Imprimir()
{
    Console.WriteLine(Nome + " " + Sobrenome);
}

Também pode ser aplicado o expression-bodied:

public void Imprimir() => Console.WriteLine(Nome + " " + Sobrenome);

O importante é que o método e propriedade somente leitura contenha uma instrução de uma linha.

Voltando ao presente

Já na versão 7 do C# foram introduzidos mais três recursos ao expression-bodied. Vamos modificar a classe apresentada anteriormente para mostrá-los:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get { return nome; }
        set { nome = value; }
    }

    public string Sobrenome
    {
        get { return sobrenome; }
        set { nome = value; }
    }

    public DateTime DataNascimento
    {
        get { return dataNascimento; }
        set { dataNascimento = value; }
    }

    public string NomeCompleto => nome + " " + sobrenome;

    public Pessoa() { }

    public Pessoa(string nome)
    {
        this.nome = nome;
    }

    ~Pessoa()
    {
        Console.WriteLine("Classe sendo destruída!");
    }

    public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Note que agora temos métodos construtores e o destrutor da classe. E é nesses métodos que a partir da versão 7, pode ser aplicado, respectivamente, o expression-bodied constructors, e o o expression-bodied destructors.

O processo é o mesmo, ambos os métodos precisam conter apenas uma instrução:

public Pessoa(string nome)
{
    this.nome = nome;
}

~Pessoa()
{
    Console.WriteLine("Classe sendo destruída!");
}

Para expression-bodied ser aplicado:

public Pessoa(string nome) => this.nome = nome;

~Pessoa() => Console.WriteLine("Classe sendo destruída!");

Além do construtor e destrutor, o expression-bodied agora pode ser aplicado aos acessores das propriedades:

public string Nome
{
    get => nome;
    set => nome = value;
}

Agora que a auto propriedade (disponível desde a versão 2 do C#) ainda é a melhor opção para reduzir código:

public string Nome { get; set; }

Mas, caso seja implementada a interface INotifyPropertyChanged, o uso deste recurso é bom para reduzir o código:

public string Nome
{
    get => nome;
    set => SetProperty(ref nome, value);
}

Não tem esse exemplo na classe acima, mas este mesmo princípio que permite o uso do expression-bodied nos acessores das propriedades, pode ser aplicado aos eventos:

private EventHandler _someEvent;
public event EventHandler SomeEvent
{
    add => _someEvent += value;
    remove => _someEvent -= value;
}

Mas este também tem a sua versão mais simples:

public event EventHandler SomeEvent

Introduzida na versão 6.

Para finalizar, aplicando os conceitos acima à classe Pessoa, ela ficará com a estrutura abaixo:

public class Pessoa
{
    private string nome;
    private string sobrenome;
    private DateTime dataNascimento;

    public string Nome
    {
        get => nome;
        set => SetProperty(ref nome, value);
    }

    public string Sobrenome
    {
        get => sobrenome;
        set => nome = value;
    }

    public DateTime DataNascimento
    {
        get => dataNascimento;
        set => dataNascimento = value;
    }

    public string NomeCompleto => nome + " " + sobrenome;

    public Pessoa() { }

    public Pessoa(string nome) => this.nome = nome;

    ~Pessoa() => Console.WriteLine("Classe sendo destruída!");

    public int Idade() => (DateTime.Now.Year - dataNascimento.Year - 1) +
            (((DateTime.Now.Month > dataNascimento.Month) ||
            ((DateTime.Now.Month == dataNascimento.Month) && 
            (DateTime.Now.Day >= dataNascimento.Day))) ? 1 : 0);
}

Conclusão

Assim como demonstrado com as tuplas, o C# 7.0 está introduzindo recursos que visam melhorar a produtividade dos desenvolvedores, sejam novos, como as já referidas tuplas ou com melhorias de recursos já existentes, como é o caso do expression-bodied.

Deixe seu comentário
Share

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

JUNTE-SE A MAIS DE 150.000 PROGRAMADORES