2015-07-01 9 views
5

Quando si tratta di vuote sequenze, sono rimasto sorpreso di scoprire che il comportamento per min o max è diversa a seconda che gli elementi di raccolta fonte sono di value type o di reference type:Perché Enumerable Min o Max è incoerente tra insiemi di riferimento e tipi di valore?

var refCollection = new object[0]; 
var valCollection = new int[0]; 
var nullableCollection = new int?[0]; 

var refMin = refCollection.Min(x => x); // null 
var valMin = valCollection.Min(); // InvalidOperationException 
var nullableMin = nullableCollection.Min(); // null 

Questa differenza di comportamenti è ben visto su .NET Core implementation of Enumerable extensions.

Questo, tuttavia, non è il caso quando si guarda Jon Skeet's MinBy extension, ad esempio, che getta su entrambi i casi come mi sarei aspettato.

La differenza di comportamento non causa solo confusioni? C'è qualche vantaggio nel restituire null per le raccolte di tipi ref?

+1

Solo per completezza, aggiungere un caso 'var nullableCollection = new int? [0];' – xanatos

+0

Buon punto! Aggiunto un caso nullable. –

+0

Mi piacerebbe anche sapere perché '(nuovo oggetto [0]). Min()' restituisce 'null' e' (new int [0]). Min() 'getta improvvisamente' InvalidOperationException' ([proof] (https://ideone.com/9NDIob)). @JonSkeet answer non risponde veramente * perché * il comportamento è diverso. – Sinatr

risposta

8

Vale la pena tenendo presente che NULLABLE tipo (entrambi i tipi di valore nullable e tipi di riferimento) si comportano in modo diverso per tipi di valore non annullabili in generale quando si tratta di Min: un valore null viene trattato come "dispersi" in generale, così non è irragionevole che il risultato del "minimo dei soli valori mancanti" sia "il valore mancante".

Ad esempio:

int?[] nullableInts = new int?[5]; // All values null 
int? min = nullableInts.Min(); // No exception, min is null 
nullableInts[3] = 2; 
min = nullableInts.Min(); // No exception, min is 2 

Per i tipi di valore non nullable, non c'è davvero la possibilità di indicare un "valore mancante" (a meno che il tipo di ritorno sono stati modificati per essere sempre un tipo nullable), da qui l'eccezione ... ma questo è ragionevolmente facile da individuare comunque, poiché per un tipo di valore non annullabile, l'unica situazione in cui non c'è un minimo è quando la fonte è vuota.

(E 'possibile che MinBy dovrebbe in realtà si comportano allo stesso modo :)

Questo è anche coerente con le conversioni in LINQ to XML:

XElement element = null; 
int? x = (int?) element; // null 
int y = (int) element; // Bang 

Fondamentalmente, si fa di una certa quantità di senso - Nessuna opzione sarebbe coerente con tutto.

+3

Vorrei aggiungere che il funzionamento di 'Min()' è coerente con il funzionamento di SQL 'MIN()' ... Il 'MIN()' di un insieme vuoto è 'NULL'. Chiaramente un tipo di valore non annullabile non può contenere 'NULL'. Quindi l'eccezione. – xanatos

+0

La coerenza con il comportamento SQL sembra un punto molto importante. –