Lanciare un'eccezione per errori che possono essere corretti

1

Dire che ho una classe come questa:

public class MyObject
{
    public List<string> MyCollection { get; set; }
}

E un metodo come questo:

public void DoSomething(MyObject object)
{
    if(object.MyCollection == null)
    {
        // MyCollection must not be null
        // Should I...

        // a)
        object.MyCollection = new List<string>();

        // b)
        throw new ArgumentException("MyCollection can not be null");
    }
}

Non ho il controllo su MyObject. Normalmente vorrei solo istanziare la raccolta nel costruttore e farla finita. Devo solo istanziare la raccolta nel mio metodo o lanciare un'eccezione?

    
posta ConditionRacer 24.07.2013 - 17:55
fonte

3 risposte

8

Ciò che hai qui si chiama istruzioni di guardia e tu dovresti lanciare un'eccezione se object.MyCollection è nullo.

Le eccezioni sono pensate per circostanze eccezionali , e dato che tu specifichi che object.MyCollection non deve essere nulla, questo sarebbe davvero eccezionale . Assicurati che l'eccezione che lanci sia di un tipo adatto (ad esempio un ArgumentNullException ) .

    
risposta data 24.07.2013 - 18:00
fonte
2

Sicuramente B, sarebbe una violazione del principio di singola responsabilità fare A poiché non è proprio questo lo scopo blocco di codice.

la mia preferenza personale è solo per fare una convalida come quella, comunque sui metodi di confine; come endpoint del servizio web o fascia API generale di una certa natura, dopo di che trovo la manutenibilità migliorata quando il codice consente un uso improprio causa solo un errore naturale (dereferenziazione per esempio nel tuo caso), in questo modo quando ciò che precedentemente era input non valido diventa input valido, c'è meno codice zangola. Inoltre, verrà generata un'eccezione se la usi, quindi perché preoccuparti di lanciare la tua eccezione?

Questa preferenza di evitare spesso le dichiarazioni di guardia è mia e mia, prendila con un pizzico di sale e solo per dire che dovresti analizzare te stesso i tuoi scenari per vedere cosa ha più senso per te, non sempre usa le istruzioni di guardia solo perché "best practice"

Detto questo, per questo caso particolare tendo a sfruttare l'operatore null coalesce; se voglio fare qualcosa con una collezione che ritengo possa essere nulla per qualche ragione, mi occuperò invece di (thatCollection ?? new List<T>()) al posto di essa, quindi finirai per trattare un elenco nullo come una lista vuota come parte del tuo le funzioni contraggono piuttosto che interferire con oggetti di qualcun altro che non sono di tua responsabilità. Questo è valido solo se non si aggiungono elementi alla collezione.

Prendo l'approccio che faccio solo per essere robusto in quanto evita il churn futuro, anche se mi accerto che sia valido comportamento entro i requisiti funzionali prima di prendere quell'approccio (lo è spesso). Ricorda:

Be conservative in what you send, be liberal in what you accept

    
risposta data 24.07.2013 - 18:01
fonte
1

Le condizioni di guardia dovrebbero, IMO, essere utilizzate solo quando non si è in grado o non si può annullare un processo. Altrimenti lascia che l'eccezione avvenga a valle dove il valore non ha senso.

Gli argomenti di una funzione dovrebbero soddisfare le esigenze della funzione, l'unico posto in grado di garantire che vengano forniti i valori corretti è il sito di chiamata.

Nel tuo esempio, come DoSomething sa che un MyCollection vuoto darà come risultato un'azione / valore accettabile come uno con una dozzina di valori in esso.

Considera se MyCollection fosse BackupToBeforeDelete - se fornisci una lista vuota, l'oggetto non viene sottoposto a backup, ma viene eliminato.

    
risposta data 25.07.2013 - 05:00
fonte

Leggi altre domande sui tag