Quando si richiama Single
o SingleOrDefault
su un IEnumerable<T>
, e ha più di un risultato, si getta InvalidOperationException
.Avendo unico e SingleOrDefault ad un'eccezione più succinta
Mentre il messaggio reale del eccezione è molto descrittivo, è problematico scrivere un fermo che gestirà solo i casi in cui i Single
/SingleOrDefault
chiamate non riescono.
public virtual Fee GetFeeByPromoCode(string promoCode)
{
try
{
return _fees.SingleOrDefault(f => f.IsPromoCodeValid(promoCode));
}
catch (InvalidOperationException)
{
throw new TooManyFeesException();
}
}
In questo scenario, se IsPromoCodeValid
getta anche una InvalidOperationException
, allora diventa ambigua su ciò che il fermo sta gestendo.
ho potuto ispezionare il messaggio di eccezione, ma vorrei evitare che, come trovo sporca per gestire il codice a seconda di un messaggio di un'eccezione.
Il mio attuale alternativa al SingleOrDefault
si presenta come la seguente:
public virtual Fee GetFeeByPromoCode(string promoCode)
{
var fees = _fees.Where(f => f.IsPromoCodeValid(promoCode)).ToList();
if (fees.Count > 1)
{
throw new InvalidFeeSetupException();
}
return fees.FirstOrDefault();
}
Tuttavia, questo codice è molto meno evidente rispetto al codice di cui sopra, in aggiunta, questo genera una query meno efficiente (se si utilizza un LINQ abilitato ORM) rispetto all'utilizzo di SingleOrDefault
.
Potrei anche fare un Take(2)
con il mio secondo esempio per ottimizzarlo un po ', ma questo ulteriormente offusca l'intento del codice.
C'è un modo per farlo senza scrivere la mia estensione per entrambi IEnumerable
e IQueryable
?
Forse 'IsPromoCode' genera un'eccezione personalizzata? Domanda interessante però. – BradleyDotNET
Hai pensato di creare un metodo di estensione ben chiamato che usa il metodo 'take (2)'? – Khan
'Potrei anche fare un Take (2) con il mio secondo esempio per ottimizzarlo un po ', ma questo in più offusca l'intento del codice. - IMO,' Take (2) 'con il controllo' fees.Count> 1 'lo rende più chiaro – Habib