2010-09-03 8 views
8

Mi sono imbattuto in questa situazione e ho pensato che fosse una buona opportunità usare la parola chiave predefinita. Ma non si compila e non riesco a pensare al perché. L'esempio che segue illustra il mio problema:Il confronto di un tipo generico con il suo valore predefinito, senza un vincolo di classe generico, dà un errore di tempo di compilazione

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

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

Otterrete un errore sulla linea 8 (" '==' operatore non può essere applicato a operandi di tipo 'TDataSource' e 'TDataSource'."). Pensavo che l'utilizzo della parola chiave predefinita eliminasse qualsiasi problema di confronto tra tipi di riferimento e tipi di valore.

L'aggiunta di un vincolo generico che limita TDataSource ai tipi di riferimento rende compilata questa parte di codice.

Qualcuno può spiegare perché il compilatore non risolverà questo per me? Non è abbastanza intelligente da vedere questo funzionerebbe?

questo è legato: Can't operator == be applied to generic types in C#?

[Edit] SLaks risposta mi ha dato qualche ispirazione, l'operatore '==' non funziona, ma la funzione Equals dovrebbe.

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

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

Questa compilazione funziona correttamente?

+0

Se stai solo cercando di capire se c'è stato un risultato, stai sbagliando perché non sarai in grado di dire la differenza tra nessun risultato e il risultato è 0. – Gabe

+0

Gabe la logica del la funzione è solo un esempio, non è utile. – JJoos

+1

La modifica può generare un'eccezione di NullReference. Devi chiamare il metodo statico 'Equals (a, b)'. – SLaks

risposta

5

Non è possibile presumere che ogni tipo di valore sovrascriva l'operatore ==. (E anche se lo facessero, non ci sarebbe alcun modo per chiamare usando farmaci generici, è un metodo statico)

Invece, si dovrebbe scrivere

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

Se result è null (e un tipo di riferimento), la chiamata ReferenceEquals restituirà true, pertanto Equals non verrà chiamato e non genererà un NullReferenceException.
Se TDataSource è un tipo di valore, lo ReferenceEquals confronterà due diversi riferimenti in scatola (che potrebbero contenere lo stesso valore, ma saranno comunque diversi), quindi passerà alla chiamata Equals.

+0

Nota che in generale, questo è il modo in cui devi confrontare due valori di tipo sconosciuto per l'uguaglianza. (questo non si applica solo alla ricerca di valori predefiniti) – Gabe

+0

Hai assolutamente ragione. Sono solo le strutture definite dall'utente che non sostituiscono l'operatore '=='? – JJoos

+0

@JJoos, se i tipi di valore sovrascrivono l'operatore '==', è buona norma sovrascrivere 'Equals()' in modo che si comporti in modo equivalente. Questo non è strettamente garantito, ma lo considererei un bug se trovassi un tipo di valore che non si comportava in questo modo. –

Problemi correlati