Ajuda com erro genérico C # - “O tipo 'T' deve ser um tipo de valor não anulável”

100

Sou novo no C # e não entendo por que o código a seguir não funciona.

public static Nullable<T> CoalesceMax<T>(Nullable<T> a, Nullable<T> b) where T : IComparable
{
    if (a.HasValue && b.HasValue)
        return a.Value.CompareTo(b.Value) < 0 ? b : a;
    else if (a.HasValue)
        return a;
    else
        return b;
}

// Sample usage:
public DateTime? CalculateDate(DataRow row)
{
    DateTime? result = null;
    if (!(row["EXPIRATION_DATE"] is DBNull))
        result = DateTime.Parse((string)row["EXPIRATION_DATE"]);
    if (!(row["SHIPPING_DATE"] is DBNull))
        result = CoalesceMax(
            result
            DateTime.Parse((string)row["SHIPPING_DATE"]).AddYears(1));
    // etc.
    return result;
}

Ele fornece o seguinte erro durante a compilação:

O tipo 'T' deve ser um tipo de valor não anulável para usá-lo como parâmetro 'T' no tipo ou método genérico 'System.Nullable <T>'
Josh Kelley
fonte
1
O erro do compilador fornece a linha de definição da função porque é onde está o erro.
SLaks

Respostas:

180

Você precisa adicionar uma T : structrestrição:

public static Nullable<T> CoalesceMax<T>
    (Nullable<T> a, Nullable<T> b) where T : struct, IComparable

Caso contrário, o C # tentará descobrir o que Nullable<T>significa e perceber que ainda não possui a restrição necessária por Nullable<T>si só. Em outras palavras, você pode tentar ligar para:

CoalesceMax<string>(...)

o que não faria sentido, pois Nullable<string>não é válido.

Jon Skeet
fonte
16

O Nullable<T>tipo tem uma restrição que exige Tser um tipo de valor ( structem C #). É por isso que o compilador está lhe informando sobre Nullable<T>e não sua função ou o site de chamada dessa função - é a Nullableclasse que é a causa raiz do erro, então isso é realmente mais útil do que se o compilador apenas apontasse para sua função e dissesse "isso não está certo, conserte!" (Imagine se você CoalesceMaxusasse vários genéricos e violasse a restrição em apenas um deles - é mais útil saber qual genérico teve sua restrição quebrada do que apenas saber que uma ou mais restrições em CoalesceMaxforam quebradas).

A solução é tornar o seu Te o deles Tcompatíveis, introduzindo a mesma restrição. Isso é feito adicionando a structrestrição, que deve vir antes de todas as interfaces / novas restrições:

public static Nullable<T> CoalesceMax<T>(Nullable<T> a, Nullable<T> b) where T : struct, IComparable{
  ...
}

fonte
6

Seu método genérico está usando um Nullable<T>.

No entanto, você não está restringindo o tipo de T, então pode acabar sendo Nullable<Form>, o que é obviamente inválido.

Você precisa alterar a restrição where T : struct, IComparablepara garantir que Tsó possa ser um tipo de valor.

SLaks
fonte
2

Não é exatamente uma resposta ao OP, mas como essa foi a primeira coisa que apareceu no Google com a mesma mensagem de erro, tive que adicionar a restrição na definição da minha classe, em vez do meu método, por exemplo,

public class MyClass<T> where T : struct
{
    public void MyMethod(T? value)
    {
    }
}
3-14159265358979323846264
fonte