Consegui localizar um artigo do Microsoft Connect que discute esse problema com alguns detalhes:
Infelizmente, esse comportamento ocorre por design e não há uma solução fácil para habilitar o uso de parâmetros de tipo que podem conter tipos de valor.
Se os tipos são conhecidos por serem tipos de referência, a sobrecarga padrão de definido no objeto testa variáveis quanto à igualdade de referência, embora um tipo possa especificar sua própria sobrecarga customizada. O compilador determina qual sobrecarga usar com base no tipo estático da variável (a determinação não é polimórfica). Portanto, se você alterar seu exemplo para restringir o parâmetro de tipo genérico T para um tipo de referência não selado (como Exceção), o compilador poderá determinar a sobrecarga específica a ser usada e o seguinte código será compilado:
public class Test<T> where T : Exception
Se os tipos são conhecidos como tipos de valor, executa testes de igualdade de valor específicos com base nos tipos exatos usados. Não há boa comparação "padrão" aqui, pois as comparações de referência não são significativas nos tipos de valor e o compilador não pode saber qual comparação de valor específica a ser emitida. O compilador pode emitir uma chamada para ValueType.Equals (Object), mas esse método usa reflexão e é bastante ineficiente comparado às comparações de valores específicas. Portanto, mesmo se você especificasse uma restrição de tipo de valor em T, não há nada razoável para o compilador gerar aqui:
public class Test<T> where T : struct
No caso apresentado, onde o compilador nem sabe se T é um tipo de valor ou referência, da mesma forma, não há nada para gerar que seja válido para todos os tipos possíveis. Uma comparação de referência não seria válida para tipos de valor e algum tipo de comparação de valor seria inesperado para tipos de referência que não sobrecarregam.
Aqui está o que você pode fazer ...
Eu validei que ambos os métodos funcionam para uma comparação genérica dos tipos de referência e valor:
object.Equals(param, default(T))
ou
EqualityComparer<T>.Default.Equals(param, default(T))
Para fazer comparações com o operador "==", você precisará usar um destes métodos:
Se todos os casos de T derivarem de uma classe base conhecida, você poderá informar o compilador usando restrições de tipo genérico.
public void MyMethod<T>(T myArgument) where T : MyBase
O compilador reconhece como executar operações no MyBase
e não lançará o "Operador '==' não pode ser aplicado aos operandos do tipo 'T' e 'T'" que você está vendo agora.
Outra opção seria restringir T a qualquer tipo que implemente IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
E, em seguida, use o CompareTo
método definido pela interface IComparable .
if (myArgument?.Equals( default(T) ) != null )
.