2011-01-31 5 views
8

Estoy tratando de escribir un comparador genérico de objetos para ordenar, pero me he dado cuenta de que no maneja la instancia donde uno de los valores que está comparando es nulo. Cuando un objeto es nulo, quiero que lo trate igual que la cadena vacía. Intenté establecer los valores nulos en String.Empty, pero luego aparece el error "El objeto debe ser del tipo String" al llamar a CompareTo() en él.¿Cómo puedo hacer que mi comparer genérico (IComparer) maneje nulos?

public int Compare(T x, T y) 
{ 
    PropertyInfo propertyInfo = typeof(T).GetProperty(sortExpression); 
    IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null); 
    IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null); 

    if (obj1 == null) obj1 = String.Empty; // This doesn't work! 
    if (obj2 == null) obj2 = String.Empty; // This doesn't work! 

    if (SortDirection == SortDirection.Ascending) 
     return obj1.CompareTo(obj2); 
    else 
     return obj2.CompareTo(obj1); 
} 

estoy bastante atascado con esto ahora! Cualquier ayuda sería apreciada.

Respuesta

15

No se puede tratar a su T como una cadena vacía a menos que su camiseta estaba limitada eficacia de ser una cadena. Lo que debe hacer es tener un plan para comparar valores nulos. Tal como

if (obj1 == null && obj2 == null) 
    return 0; 
else if (obj1 == null) 
    return -1; 
else if (obj2 == null) 
    return 1; 
else 
    return obj1.CompareTo(obj2); 
+0

Gracias Anthony, eso funciona un placer! Realmente no sé por qué nunca parece detectar la solución simple ... – NickG

0

Dado que T es un tipo genérico, no puede asignarle un valor de String; solo puede asignarle un valor de tipo T. Si solo va a utilizar esto para comparar cadenas, use String en lugar de T. De lo contrario, agregue una comprobación nula y decida dónde debe caer el orden null.

+0

Eso es lo que estaba tratando de hacer (el segundo), pero yo no puedo hacer nada para trabajar. No sé cómo declarar un nuevo objeto T vacío válido para que lo compare en lugar del nulo. ¡Todavía estoy confundido por los genéricos para ser honesto! – NickG

+1

@Nick, un 'T' predeterminado para un tipo de referencia seguiría siendo nulo. Podría obtenerse una 'T' instanciada pero por lo demás vacía si 'T' tuviera una restricción 'donde T: new()', que le permitiría crear una 'T' dentro de su método, pero también significaría que todo 'T 'los candidatos tendrían que tener un constructor público sin parámetros. En esta situación particular, no debe hacer que esto sea un requisito, ya que debería poder tratar eficazmente los nulos en su código. –

0
IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null) ?? ""; 
IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null) ?? ""; 

Esto significa básicamente que obj1 será ahora el valor de propertyInfo.GetValue (x, null) o, si que pasa a ser nulo, obj1 habrá "".

o si el problema es que el GetValue se estrella en nulo que podría hacer algo como:

IComparable obj1 = ""; 
try { obj1 = (IComparable)propertyInfo.GetValue(x, null); } catch {} 
1
if (SortDirection == SortDirection.Ascending) 
    return Comparer<T>.Default.Compare(obj1, obj2); 
else 
    return Comparer<T>.Default.Compare(obj2, obj1); 
Cuestiones relacionadas