2010-02-02 8 views
8

Quiero poder verificar si un valor es el predeterminado para su tipo de valor. Idealmente, me gustaría decir:Verificación del valor por defecto utilizando los tipos genéricos

DoSomething<TValue>(TValue value) { 
    if (value == default(TValue)) { 
     ... 
    } 
} 

Sin embargo, el compilador se queja de que no puede hacer una comparación == en TValue y TValue. Esta es la mejor solución que he encontrado hasta el momento:

DoSomething<TValue>(TValue value) { 
    if (value == null || value.Equals(default(TValue))) { 
     ... 
    } 
} 

¿Hay una manera más elegante/correcta de hacer esto?

Respuesta

37
public bool EqualsDefaultValue<T>(T value) 
{ 
    return EqualityComparer<T>.Default.Equals(value, default(T)); 
} 
4

Agregue la restricción de clase y debería funcionar.

public void Test<T>(T instance) where T : class 
{ 
    if (instance == default(T)) 
    { 

    } 
} 

O si solo quiere tipos de valores puede hacerlo.

public void Test<T>(T instance) where T : struct, IEquatable<T> 
{ 
    if (instance.Equals(default(T))) 
    { 

    } 
} 
+4

Si arroja la restricción 'clase', también puede comprobar contra' nulo' ... –

+0

@Marc - Lo sé, en este punto es una cuestión de preferencia. – ChaosPandion

+0

Espero que esto funcione para cualquier tipo, incluidos los tipos de valor y clase. – StriplingWarrior

1

Su problema es que un tipo genric (sin limitación) tiene que ser "compilables" para cualquier tipo. Como no todos los tipos tienen un operador ==, su código no se compilará.

Una forma de resolverlo es agregar una restricción de clase, sin embargo, desde su uso predeterminado (TValue) que sugeriría que desea que el código funcione con otros tipos. (De lo contrario sólo tiene que utilizar nulo en lugar de por defecto (TValue). Una solución podría ser algo similar a lo que Bryan Watts sugiere

bool DoSomething<TValue>(TValue value) { 
    return EqualityComparer<TValue>.Default.Equals(value, default(TValue)); 
} 

o podría envolverlo en un método de extensión

bool IsDefault<TValue>(this TValue value) { 
    return EqualityComparer<TValue>.Default.Equals(value, default(TValue)); 
} 
0

Agregando a la respuestas publicadas aquí, creo que también debemos ser capaces de especificar si desea que el valor de referencia o de la igualdad:

static public class MyGenericHelper 
{ 
    static public bool EqualsByValue<T>(T x, T y) 
    { 
     return EqualityComparer<T>.Default.Equals(x, y); 
    } 

    static public bool EqualsByReference<T>(T x, T y) 
    { 
     if (x is ValueType) return EqualityComparer<T>.Default.Equals(x, y) // avoids boxing 

     return Object.ReferenceEquals(x, y); 
    } 
} 

a todos nos encanta crear y mantener un trillón poco h métodos elper como ese no nosotros: ->

+0

Parece que 'typeof (T) .IsValueType' sería preferible a' x is ValueType' tanto en términos de legibilidad como de rendimiento. ¿Me equivoco? – StriplingWarrior

+1

Quizás la legibilidad es una cuestión de gusto a veces. : -> ... 'x es ValueType' simplemente intuitivamente" se siente más rápido "para mí, porque' typeof (T) .IsValueType' tiene que recuperar la muy pesada instancia 'Type', y el reflector revela que' .IsValueType' property llama a un método virtual que implementado en 'RuntimeType' finalmente llama a algo externo. Pero entonces, ¿quién soy yo para juzgar? No soy un iniciado. Incluso pueden compilar hasta las mismas instrucciones. Tal vez es una buena pregunta nueva. ;-) ... O podrías hacer algunas pruebas de rendimiento tú mismo si es crucial. – herzmeister

+0

No es crucial, pero tenía curiosidad, así que hice una prueba rápida y ¡tienes razón! 'x is ValueType' toma aproximadamente un tercio del tiempo. – StriplingWarrior

Cuestiones relacionadas