Pregunta La comparación de un tipo genérico con su valor predeterminado, sin una restricción de clase genérica, da un error de tiempo de compilación


Me encontré con esta situación y pensé que era una buena oportunidad para usar la palabra clave predeterminada. Pero no compila y no puedo pensar por qué. El siguiente ejemplo ilustra mi problema:

public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result != default(TDataSource);
    }
}

Aparecerá un error en la línea 8 ("Operator '==' no se puede aplicar a operandos de tipo 'TDataSource' y 'TDataSource'."). Pensé que el uso de la palabra clave predeterminada eliminaría cualquier problema de comparación entre los tipos de referencia y los tipos de valores.

Agregar una restricción genérica que limita TDataSource a los tipos de referencia hace que este fragmento de código se compile.

¿Alguien puede explicar por qué el compilador no solucionará esto por mí? ¿No es lo suficientemente inteligente como para ver que esto funcionaría?

Esto está relacionado: ¿No se puede aplicar el operador == a los tipos genéricos en C #?

[Editar] La respuesta de SLaks me dio algo de inspiración, el operador '==' no funcionará, pero la función Equals debería funcionar.

    public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result.Equals(default(TDataSource));
    }
}

¿Esto compilaría esto funcionaría correctamente?


8
2017-09-03 13:29


origen


Respuestas:


No puede suponer que cada tipo de valor anula el == operador. (E incluso si lo hicieran, no habría forma de llamarlo usando genéricos, es un método estático)

En cambio, debes escribir

    return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
          || result.Equals(default(TDataSource)));

Si result es null (y un tipo de referencia), el ReferenceEquals la llamada volverá true, asi que Equals no será llamado y no lanzará un NullReferenceException.
Si TDataSource es un tipo de valor, el ReferenceEquals comparará dos referencias en caja diferentes (que pueden contener el mismo valor, pero seguirán siendo diferentes), por lo que pasará a la Equals llamada.


5
2017-09-03 13:31