C#  -  Default(T) vs default


  Você sabe me dizer a diferença entre o operador default e Default(T).

No C# uma expressão de valor default vai produzir o valor padrão do tipo sendo que existem dois tipos de expressões de valor default: o operador default e o literal default.

O operador default usa um argumento que tem que ter o nome do tipo ou um parâmetro do tipo e pode ser usado para inicializar a instância de um objeto :

O valor padrão depende do tipo de dado. Por exemplo:


int defaultInt = default; // Isso atribui 0, que é o valor padrão para int bool
bool defaultBool = default; // Isso atribui false, que é o valor padrão para bool
 

O operador default é útil para inicializar variáveis com seus valores padrão ou para verificar se uma variável contém o valor padrão.

A partir do C# 7.1, você pode usar o literal default para produzir o valor padrão de um tipo quando o compilador puder inferir o tipo de expressão. A expressão literal default produz o mesmo valor que a expressão default(T), em que T é o tipo inferido. Você pode usar o literal padrão em qualquer um dos seguintes casos:

Default com Generics

O método Default(T) é um método genérico que permite obter o valor padrão para um tipo genérico T. Você pode usá-lo quando você precisa do valor padrão para um tipo específico, mas o tipo é desconhecido em tempo de compilação ou determinado dinamicamente.


int defaultValue = Default<int>(); // Isso atribui 0, o valor padrão para int
bool defaultValue = Default<bool>(); // Isso atribui false, o valor padrão para bool
 

Você deve chamar Default<T>() especificando o tipo entre os parênteses angulares <T>. O método Default(T) é útil quando você precisa obter o valor padrão de um tipo genérico em tempo de execução.

Ajém disso, "Default" representa o valor padrão do parâmetro T nas instruções genéricas. Em vários casos, a palavra-chave default é desconhecida e achamos desnecessária ou sua funcionalidade a torna nula.

No entanto existem cenários com as classes genéricas em que a palavra-chave default pode ser útil e pode facilitar nosso trabalho e tornar o código mais seguro.

A seguir temo um exemplo de um método genérico com dois parâmetros ref do tipo T que altera seus valores na implementação:

public static void AlteraValores<T>(ref T a, ref T b)
{
    T _a = a;
    T _b = b;

    a = _b;
    b = _a;
}

No método AlteraValores não temos um filtro de restrição genérico para que T seja qualquer tipo (tipo de referência ou tipo de valor)

Podemos validar se os parâmetros foram inicializados usando o código seguir:

public static void AlteraValores<T>(ref T a, ref T b)
{

    if (a.Equals(null) || b.Equals(null))
    {
        throw new ArgumentException("....");
    }

    T _a = a;
    T _b = b;

    a = _b;
    b = _a;
}

Mas usando esta abordagem não estamos verificando os tipos de valor padrão que pode causar uma execução incorreta para contornar podemos fazer assim:

static void NovoAlteraValores<T>(ref T a, ref T b)
{

    if (a.Equals(default(T)) || b.Equals(default(T)))
    {
        throw new ArgumentException("Temos aqui os valores default para T");
    }

    T _a = a;
    T _b = b;

    a = _b;
    b = _a;
}

Neste outro exemplo temos uma classe genérica Teste que requer um parâmetro de classe com um construtor público sem parâmetros.

No exemplo a seguir,  método GetOrDefault retorna uma nova instância do parâmetro de tipo. Se o tamanho do campo for igual a 0, ele retornará o valor padrão.

using System.Text;

Console.WriteLine("\n### Usando Default ###\n");

Teste<StringBuilder> teste = new Teste<StringBuilder>();

Console.WriteLine(teste.GetOrDefault() == null);

System.Console.Read();

class Teste<T> where T : class, new()
{
    int _size;

    public T GetOrDefault()
    {
        // Usando default em um método de cuma classe genérica
        return _size == 0 ? default(T) : new T();
    }
}

O resultado obtido será True visto que tamanho será igual a zero e assim teremos o valor padrão do tipo StringBuilder retornado e isso é um valor null que é o valor padrão para o tipo de referência.

Em resumo, o operador default é usado para obter o valor padrão de um tipo de dado conhecido em tempo de compilação, enquanto o método Default(T) é usado para obter o valor padrão de um tipo genérico, que pode ser determinado em tempo de execução. Ambos são úteis em situações diferentes, dependendo dos requisitos do seu código.

E estamos conversados....

"Portanto nós também, pois que estamos rodeados de uma tão grande nuvem de testemunhas, deixemos todo o embaraço, e o pecado que tão de perto nos rodeia, e corramos com paciência a carreira que nos está proposta"
Hebreus 12:1

Referências:


José Carlos Macoratti