2011-01-31 18 views
8

Sto provando a scrivere un comparatore di oggetto generico per l'ordinamento, ma ho notato che non gestisce l'istanza in cui uno dei valori che sta confrontando è nullo. Quando un oggetto è nullo, voglio che lo tratti allo stesso modo della stringa vuota. Ho provato a impostare i valori nulli su String.Empty ma poi ottengo un errore di "Oggetto deve essere di tipo String" quando si chiama CompareTo() su di esso.Come posso rendere null il mio comparatore generico (IComparer)?

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); 
} 

Sono abbastanza bloccato con questo ora! Qualsiasi aiuto sarebbe apprezzato.

risposta

15

Non si può trattare il vostro T come una stringa vuota a meno che il T è stato effettivamente costretto ad essere una stringa. Cosa si dovrebbe fare è un piano per confrontare null. Come ad esempio

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

Grazie Anthony, è una sorpresa! Non so davvero perché non sembro mai individuare la soluzione semplice ... – NickG

0

Dato che T è un tipo generico, non è possibile assegnargli un valore String; è possibile assegnarlo solo a un valore di tipo T. Se lo utilizzerai solo per confrontare le stringhe, utilizza String anziché T. Altrimenti, aggiungere il controllo nullo e decidere dove deve andare l'ordine null.

+0

Questo è quello che stavo cercando di fare (il secondo), ma non riesco proprio a ottenere qualcosa da lavorare. Non so come dichiarare un nuovo oggetto T vuoto vuoto per poterlo confrontare al posto del null. Sono ancora confuso dai generici per essere onesti! – NickG

+1

@Nick, un 'T' predefinito per un tipo di riferimento sarebbe ancora nullo. Si potrebbe ottenere un 'T' istanziato, ma altrimenti vuoto, se' T' avesse un vincolo 'dove T: new()', che ti permetterebbe di istanziare un 'T' all'interno del tuo metodo, ma significherebbe anche che tutti' T 'I candidati dovrebbero avere un costruttore pubblico senza parametri. In questa particolare situazione, non dovresti renderlo un requisito in quanto dovresti essere in grado di gestire efficacemente i valori null nel tuo codice. –

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

Ciò significa che obj1 sarà ora il valore di propertyInfo.GetValue (x, null) o, se ciò sembra essere nullo, ogg1 sarà "".

o se il problema è che la GetValue si blocca sul nulla si potrebbe fare qualcosa di simile:

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); 
Problemi correlati