Pude localizar un artículo de Microsoft Connect que analiza este problema con cierto detalle:
Desafortunadamente, este comportamiento es por diseño y no existe una solución fácil para permitir el uso de parámetros de tipo que puedan contener tipos de valor.
Si se sabe que los tipos son tipos de referencia, la sobrecarga predeterminada de las variables definidas en el objeto prueba la igualdad de referencia, aunque un tipo puede especificar su propia sobrecarga personalizada. El compilador determina qué sobrecarga usar en función del tipo estático de la variable (la determinación no es polimórfica). Por lo tanto, si cambia su ejemplo para restringir el parámetro de tipo genérico T a un tipo de referencia no sellado (como Exception), el compilador puede determinar la sobrecarga específica a utilizar y el siguiente código se compilaría:
public class Test<T> where T : Exception
Si se sabe que los tipos son tipos de valor, realiza pruebas de igualdad de valor específicas basadas en los tipos exactos utilizados. Aquí no hay una buena comparación "predeterminada" ya que las comparaciones de referencia no son significativas en los tipos de valor y el compilador no puede saber qué comparación de valor específica emitir. El compilador podría emitir una llamada a ValueType.Equals (Object) pero este método utiliza la reflexión y es bastante ineficiente en comparación con las comparaciones de valores específicos. Por lo tanto, incluso si tuviera que especificar una restricción de tipo de valor en T, no hay nada razonable para que el compilador genere aquí:
public class Test<T> where T : struct
En el caso que presentó, donde el compilador ni siquiera sabe si T es un valor o un tipo de referencia, tampoco hay nada que generar que sea válido para todos los tipos posibles. Una comparación de referencia no sería válida para los tipos de valor y algún tipo de comparación de valor sería inesperada para los tipos de referencia que no se sobrecargan.
Esto es lo que puedes hacer ...
He validado que ambos métodos funcionan para una comparación genérica de tipos de referencia y valor:
object.Equals(param, default(T))
o
EqualityComparer<T>.Default.Equals(param, default(T))
Para hacer comparaciones con el operador "==", deberá utilizar uno de estos métodos:
Si todos los casos de T derivan de una clase base conocida, puede informar al compilador utilizando restricciones de tipo genérico.
public void MyMethod<T>(T myArgument) where T : MyBase
El compilador luego reconoce cómo realizar operaciones MyBase
y no arrojará el "Operador '==" no se puede aplicar a los operandos de tipo' T 'y' T '' error que está viendo ahora.
Otra opción sería restringir T a cualquier tipo que implemente IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
Y luego use el CompareTo
método definido por la interfaz IComparable .
if (myArgument?.Equals( default(T) ) != null )
.