Dev & EngARTICLE

What's New in C# 8.0: Default Interface Members

One of the most anticipated features for C# 8.0 has been made available for testing: Default Interface Members. Renato Groffe explains it all in this article.

What's New in C# 8.0: Default Interface Members
Image: Renato Groffe

This past May 2019 was quite eventful within the .NET community, with the announcement of new updates to Visual Studio 2019 and .NET Core 3.0. With these new versions, one of the most anticipated features for C# 8.0 was also made available for testing: Default Interface Members.

Now allowing method and property implementations to be declared within an interface, this new feature helps avoid breaking code when new members need to be added to these structures.

In the listing below we have an example involving the IPrestadorServico interface, along with the PessoaFisica and PessoaJuridica classes as two possible implementations of it:

csharp
namespace ExemploDefaultInterfaceMembers
{
    public interface IPrestadorServico
    {
        string Codigo { get; }
        string Nome { get; set; }
    }

    public class PessoaFisica : IPrestadorServico
    {
        public string CPF { get; set; }
        public string Codigo { get => CPF; }
        public string Nome { get; set; }
    }

    public class PessoaJuridica : IPrestadorServico
    {
        public string CNPJ { get; set; }
        public string Codigo { get => CNPJ; }
        public string Nome { get; set; }
    }
}

We can test the use of Default Interface Members with the structures presented here as an example through the following changes:

  • Declaring the property PossuiCNPJ in IPrestadorServico and assigning true as the default value. This same property can still be redefined in PessoaFisica to return false, while no change will occur in PessoaJuridica;
  • With the ObterDescricaoGeral method, without any modifications being made to PessoaFisica and PessoaJuridica.
csharp
namespace ExemploDefaultInterfaceMembers
{
    public interface IPrestadorServico
    {
        string Codigo { get; }
        string Nome { get; set; }
        bool PossuiCNPJ { get => true; }

        string ObterDescricaoGeral()
        {
            return $"{Codigo}, {Nome}, é uma Empresa: " +
                (PossuiCNPJ ? "Sim" : "Não");
        }
    }

    public class PessoaFisica : IPrestadorServico
    {
        public string CPF { get; set; }
        public string Codigo { get => CPF; }
        public string Nome { get; set; }
        public bool PossuiCNPJ { get => false; }
    }

    public class PessoaJuridica : IPrestadorServico
    {
        public string CNPJ { get; set; }
        public string Codigo { get => CNPJ; }
        public string Nome { get; set; }
    }
}

It's important to note that members with a default implementation that have not been redefined in classes deriving from an interface will not be available for direct access. What does this mean in practice for this last example?

With a reference based on PessoaFisica or PessoaJuridica, the ObterDescricaoGeral method will not be available. Variables declared as being of type IPrestadorServico will have access to this method.

The PossuiCNPJ property, in turn, will be available only for variables declared as being of the PessoaFisica class or based on the IPrestadorServico interface. This property will not be available for direct access via a reference of type PessoaJuridica.

The image below illustrates these points:

The next listing shows an example of using the PessoaFisica and PessoaJuridica types in a Console Application, with the ImprimirDadosPrestador method receiving as a parameter references based on these classes:

csharp
using System;

namespace ExemploDefaultInterfaceMembers
{
    class Program
    {
        private static void ImprimirDadosPrestador(
            IPrestadorServico prestador)
        {
            Console.WriteLine(prestador.ObterDescricaoGeral());
        }

        static void Main()
        {
            var pessoaFisica = new PessoaFisica();
            pessoaFisica.CPF = "22222222222";
            pessoaFisica.Nome = "Testando Pessoa Física";
            ImprimirDadosPrestador(pessoaFisica);
            
            var pessoaJuridica = new PessoaJuridica();
            pessoaJuridica.CNPJ = "33444555777788";
            pessoaJuridica.Nome = "TestePessoaJuridica";
            ImprimirDadosPrestador(pessoaJuridica);
        }
    }
}

Below is the result of running this project:

If you want to learn more about other new features included in C# 8.0, check out the following post, where I've grouped together all the content I've been producing about this version:

C# 8.0 - Reference Guide: articles, videos, and usage examples

And also the recording of a recent presentation on Canal .NET, in which MVP André Secco and I presented the new features of C# 8.0 in detail:


References

What's new in C# 8.0 - C# Guide | Microsoft Docs

Default Interface Methods - GitHub

Translated from the Brazilian Portuguese original · Read the original