Transcript for:
Lezione sulla Programmazione e Errori

Ho bisogno di un attimo di aiuto da parte vostra come in qualità di badanti, ok? Perché non mi ricordo esattamente che cosa abbiamo visto e che cosa no, e il tempo non è infinito, quindi se vi racconto qualche cosa, oltre a annoiarvi a morte, non ci sta il resto. Quindi, dovreste riuscire a vedere adesso le slide.

Questo sono sicura che l'abbiamo fatto, poi a demo, questa più o meno c'era. gli statement li abbiamo fatti giusto? abbiamo già parlato del foreach, dello switch non abbiamo parlato del goto e questo resta lì poi ok non abbiamo parlato dello using o abbiamo parlato dello using?

si l'abbiamo già parlato grande i modificatori di accesso ve li lascio sulla slide perché che esistono si sa quali sono ne abbiamo vagamente parlato Almeno lì, qua ne avete una visione sistematica. Questo disegnino vi dovrebbe dare la gerarchia delle cose, che è la cosa più semplice. Public lo vedono tutti, internal protected lo vedono quelli nelle classi e nella sottoclasse, oppure le cose che stanno nello stesso assembly, protected è solo sulla gerarchia delle classi, quindi classi sottoclassi, internal è solo sulla gerarchia degli assembly. all'interno dello stesso assembly, private protected invece è l'intersezione dei due, quindi classe o sottoclasse nello stesso assembly e privato soltanto all'interno della classe. Colgo l'occasione per ricordarvi che nella stessa classe non vuol dire nello stesso oggetto, cioè un campo che è privato non è che lo possono modificare solo il proprietario di quel campo, lo può modificare qualunque oggetto della stessa classe.

Questa è una cosa che spesso... non viene tanto istintiva e si tende a dimenticarsi var l'abbiamo visto le property estensivamente queste di nuovo è un po di una slide con un po di sintassi su come si le scorciatoie per costruire gli oggetti quando costruite un array questo la forse l'abbiamo già visto poi tra graffe mettete gli elementi si deduce sia il tipo che la dimensione Scusate, una domanda per alzata di mano. Gli array durante la loro vita possono cambiare dimensione? Cioè io creo un array da 10, poi può diventare un array da 12?

È chiaro a tutti? Allora lo potete spiegare a quelli dell'anno scorso, per favore, che nell'ultimo scritto si sono suicidati in massa con questa cosa? No, mi è venuto il dubbio che, ho detto, magari hanno visto al Python le cose cambiano?

No. Questa l'abbiamo vista, assolutamente sì. I metodi locali invece mancano, o abbiamo parlato anche dei metodi locali?

Non abbiamo parlato dei metodi locali, parleremo dei metodi locali. Costanti anche, non le abbiamo fatte, le eccezioni no, e ne riparliamo, gli illumini invece sì. E lo using no, penso. ok spero di ricordarmi tutte le cose che devo fare quindi cominciamo con cose facili allora dicevamo che gli statement sono più o meno uguali in c sharp e in java e quindi in particolare ad esempio se io voglio fare un if Volevo farvi un esempio per essere sicure che siamo sulla stessa pagina, come si suol dire.

Ho visto che non a tutti è chiarissimo perché alcune cose si fanno in un modo piuttosto che nell'altro. L'if, tra parentesi tonde, vuole un'espressione booleana, quindi se avete un qualche cosa che restituisce un booleano ce l'avete già. Però ho notato che tantissimi fanno questa cosa qua.

Allora, fa così schifo ai sassi che anche... Visual Studio ve lo segnala che non va bene, ok? Perché non va bene?

Perché è meno efficiente ed è completamente privo di senso. O credete che tra parentesi tonde potete mettere un'espressione booleana e allora vi bastava l'invocazione del metodo, o se non ci credete, beh, ma il bool method uguale uguale true è un'espressione booleana, allora non può stare lì, ci va un altro uguale uguale true, che così avete un'espressione booleana che non può stare lì. quindi ci va un altro uguale, uguale true cioè non vi fermate mai cioè o l'espressione booleana da sola va bene o se l'unica cosa che può essere un uguale, uguale true siccome quella è un'espressione booleana ce ne vuole un altro e un altro e un altro e non si termina mai più quindi questa è veramente vuol dire non avere capito come funzionano le espressioni booleane qui questo no ho esagerato Questo va benissimo come logica, nel senso se l'espressione booleana è vera faccio qualche cosa, altrimenti faccio qualcos'altro. Ma se invece di questo, poi qua ci aggiungo un return, perché ho fatto tutto quello che dovevo, l'else di nuovo non ha ragione di esistere, perché?

Perché se sono entrata nell'if, ho fatto la stampa e poi sono uscita dalla funzione tutto quello che viene da lì in avanti è codice irraggiungibile quindi questo else introduce un salto che non serve a niente perché se la condizione vera sono uscita dalla funzione se la condizione falsa devo fare l'else quindi questo else diventa superfluo tutte le volte che qua avete un qualche cosa che cambia il flusso di controllo se avete un return avete un sollevato un eccezione in ogni caso non andate a fare le righe sotto quindi l'else è inutile tutto quello che inutile nel codice è dannoso nel caso specifico l'else è dannoso perché perché vi porta il codice indentato in dentro lo vedete che viene in qua e quindi per ogni condizione in più in più che mettete create due cose la prima avete meno spazio in cui scrivere la seconda che io che rileggo che leggo questo codice o voi quando leggete questo codice fra i prossimi cinque anni se ci avete messo un else vi dovete chiedere perché ci avete messo l'else sotto quale condizione vi serviva quell'else quindi andate a spremere il cervello del perché penso che non ci sia il return no che non funziona non funziona cosa succede cioè quell'else ha tanto senso quanto se qua ci mettessi var people uguale 99 lì è del tutto inutile perché perché se sono uscito quel var people non lo faccio e analogamente se sono uscito per forza di cose non faccio il pezzo sotto quindi tanto vale non metterci l'else poco ma questi errori sono tutti errori che vengono penalizzati quando correggono gli iscritti perché sono errori veramente di butto il codice a caso senza ragionare senza pensare Vado per tentativi, non ho capito veramente cosa sto facendo. Quindi non ve li sto raccontando per fantasia, ve li sto raccontando perché soprattutto se siete magari vicino a un valore soglia, possono essere quelli che vi fanno restare sopra se li fate giusti, sotto se li fate sbagliati. Quindi memorizzate, cioè l'if funziona esattamente come in Java. Ah, scusate, e ovviamente questo è il vero inutile. C sharp come è vero in Java è stupido anche in Java metterlo uguale uguale true, è stupido anche in Java mettere l'else quando il controllo salta fuori non è perché è specifico di C sharp è stupido in C è stupido in qualunque linguaggio che abbia lift and else poi, ho già dimenticato che dovevo fare, metodi locali Ci sono, quando strutturate i vostri metodi, allora supponete di avere un metodo molto complicato, che è sensato strutturare in sottopezzi, quindi avete dei metodi che sono ausiliari a questo metodo.

Il problema è quale visibilità assegnare a questi metodi e dove mettere questi metodi. La visibilità, la regola della visibilità è sempre il meno possibile. Sempre il meno possibile perché più superficie d'attacco date, cioè dove l'attacco magari semplicemente l'attacco dell'idiota che sbaglia, non del genio che deliberatamente sta attaccando il vostro software, ma più roba è pubblica, più roba la gente vede e più cose possono modificare, cambiare e pasticciare. Quindi sicuramente la visibilità è il meno possibile, perciò se un metodo ausiliario che riutilizzate in altri punti della vostra classe, probabilmente privato è la cosa giusta, un livello di visibilità. Ma ci sono dei casi in cui è ancora più stretto, non è che è una cosa che non vi serve al di fuori della classe, è una cosa che avete proprio introdotto perché il metodo che stavate scrivendo era lungo 2000 righe, non era leggibile e quindi avete fatto una cosa.

che avete estratto un pezzo della logica del vostro algoritmo, gli avete dato un nome perché così è più facile leggere le cose, ma non avrete mai una seconda chiamata, quella cosa lì viene chiamata solo in questo metodo. Pensate a due esempi contrastanti, avete il controllo sui parametri, in tutta la vostra classe Le cose maggiori di 0 vanno bene, quelle minori di 0 non vanno bene. Avete un metodo ausiliario interno alla vostra classe che controlla se una cosa è maggiore di 0 e lo richiamate in 27 diversi metodi. Privato all'interno della classe va benissimo.

Avete invece un sistema per cui state implementando un algoritmo e a seconda dell'input che hanno dato a quel metodo... a seconda del parametro del metodo, ci sono tanti tanti casi differenti, complicati, che però hanno una logica, che so, l'input può essere ad esempio un enum, e a seconda del colore che vi viene passato come parametro, se è blu fate una cosa, se è rosso ne fate un'altra, che sono proprio cose molto diverse. Se è blu faccio partire una chiamata, se è rosso crea una base di dati.

Tanto tanto codici in entrambi i casi. Allora, è sensato il fatto di dire, ho dei sottometodi, faccio chiamata, creo database, all'interno di che cosa? Se lo uso soltanto all'interno del mio metodo, la visibilità più logica è solo all'interno del mio metodo. Perché?

Per due ragioni. La prima è il fatto che così non sporco fuori. Fuori non lo possono vedere, non lo possono usare.

Se poi mi serve cambiarlo, lo posso fare liberamente, perché sono sicuro che nessun altro lo sta usando. Quindi dal punto di vista della mantenibilità, il fatto di avere una cosa con una visibilità limitata vi aiuta sempre. La seconda cosa è, ricordatevi sempre che i codici si scrive marginalmente per farli eseguire. No, in realtà il primo scopo dovrebbe essere per farli eseguire, ma immediatamente sotto e dal punto di vista del costo quasi alla pari, si scrive per leggerlo.

Perché lo scrivete una volta e lo leggete 200. Quindi meno cose sono visibili, meno cose che uno che legge il vostro codice sa che deve imparare. Quindi se io a livello di metodi della classe non vedo comparire i metodi ausiliari che servono all'interno di un singolo metodo, se non devo proprio entrare e capire come fa l'algoritmo di quello specifico metodo, quei metodi per me non esistono. Cioè i metodi ausiliari è come se non ci fossero.

Se me li mettete come privati all'interno della classe, quando io leggo la classe, per forza di cose, dico oh, ci sono questi 27 metodi, andiamo un po'a vedere che cosa fanno, se mi servono, dove mi servono, dove vengono usati e perché. Perché io sto cercando di capire la classe nel suo complesso. Quindi, se sono allo stesso livello della classe, me li leggo. Se invece sono nascosti nell'implementazione di un metodo, no. Seguendo questo criterio, In C Sharp quello che potete fare è questo, vi siete dentro un metodo e dentro a questo metodo ne potete ridichiarare un altro.

Quindi adesso questo M lo posso chiamare all'interno della mia... del mio metodo, ma se vado all'interno di un'altra, qua ad esempio, M non c'è, sperando di non aver beccato, sì, M non c'è, non c'è perché l'ho definito dentro al MyBullMethod e la sua scope è il MyBullMethod. Quindi tutte le volte che dovete fare un metodo ausiliario ponetevi il problema di chi ha bisogno di questo metodo ausiliario, se chi ha bisogno del metodo ausiliario sono altri metodi.

Tanti, plurale, all'interno della classe, lo mettete nella classe privata. Se la risposta è uno specifico metodo, lo mettete dentro al metodo che lo usa. A questo punto dove lo mettete di solito si mette in fondo. tradizionalmente lo stile prevede che perché perché questa è una lettura vi permette la lettura top down io leggo come fatto il my bull metodo a my bull metodo chiamo metodo m che se si chiama m di vento scema ma se avessi un nome descrittivo mi permetterebbe di andare avanti vado avanti e poi solo se dei dubbi su qual è la vera implementazione di quel metodo continuo e leggo l'implementazione una cosa che resta sempre in dubbio, cioè che è soggetta a diverse scuole di pensiero. Cosa faccio se anche il mio metodo M, supponete che dentro M poi voglio fare più più A, facciamola facile.

Lo posso fare? Sì, lo posso fare perché A è un parametro di myBullMethod, quindi la sua visibilità è per tutto il metodo, e quindi tutte le cose che sono visibili nello scopo in cui sto dichiarando M sono visibili anche dentro M, perciò lo posso usare. Posso fare così, oppure posso fare così. Qual è la differenza fra questi due approcci? In un caso qui ho ridefinito il parametro, quindi vuol dire che è un altro parametro, viene creata la locazione, viene inizializzato, cioè dal punto di vista computazionale ha un minimo di peso in più, non stiamo parlando di ci mette due ore in più a eseguire il codice, però c'è quel lepsilon di complicazione in più.

Il vantaggio è che quando leggo questo non devo tornare su e guardare chi diavolo è A. B è uno dei parametri di M, quindi sono belle che ha posto, lo so, è lui. Il vantaggio dell'altro approccio è il fatto che ho una A che è uguale, ha sempre lo stesso senso dappertutto.

La cosa che vi consiglierei di evitare è questa. Perché lo potete fare, sì, però vedete questo parametro A nasconde questo parametro A e nulla vi dice che qua l'ho dovuto chiamare con A, potevo fare anche A più 98, giusto? Nel qual caso questa A e questa A sono sempre due A diverse, con due locazioni diverse, ma non necessariamente contengono lo stesso valore, perché a seconda di con che cosa ho chiamato, su quale parametro ho chiamato M, su quale espressione ho chiamato M, possono essere completamente disalineate come in questo caso quindi scegliete voi se vi piace di più lo stile in cui risparmiate spazio diciamo e non dichiarate le variabili come parametri e usate direttamente le cose che sono globali rispetto a m perché sono parametri di by my bimbo oppure preferite dichiarare dei parametri dentro alla m dichiarare tutto dentro la M tutti i parametri che la M è sensato più usi.

Entrambe le soluzioni sono ragionevoli. L'altra cosa che vi sconsiglio caldamente da fare è questa, cioè la versione ibrida, in cui la M... ha un parametro che c'entra con la A, perché qua lo chiamerò ad esempio con la A, ma poi A è anche visibile dentro a M, quindi ho il rischio di crearmi un bellissimo aliasing fra una A e l'altra A, nella testa, non è un aliasing nel senso tecnico del termine, perché essendo cose per valore, ovviamente sono locazioni diverse e succedono cose diverse. Ma se nella mia testa, se quello è un altro parametro, non mi aspetto che contenga la A, mi sembra che crei veramente, complichi le cose. Perciò il mio suggerimento è, nessun parametro e usate direttamente i parametri del metodo esterno, oppure parametri tutti quelli che vi servono, non accedete a nulla di globale dentro al metodo.

eccezioni questa è un'altra cosa su cui potrei iniziare in maniera molto semplice dicendovi le eccezioni sono gestite con esattamente come in java quindi si sollevano si catturano si catturano potete avere si catturano con un blocco tra i catch potete avere tanti cash per un try I catch vengono eseguiti dall'alto in basso in ordine di tipo, il primo che viene catturato, il primo che cattura l'eccezione termina l'esecuzione del blocco tra i catch e quindi quelli dopo non vengono più presi in considerazione, ragione per la quale i blocchi catch vanno messi in ordine crescente di tipo, non dovete mai mettere un sovratipo e poi un catch con sottotipo sotto. Questo viene tutto da Java. E questo di solito vi è estremamente chiaro, non ho mai trovato in tanti anni persone che non lo sapessero.

Mi sembra che sia una cosa che viene acquisita benissimo nel corso del secondo anno e siamo contenti. Poi però ci sono delle stranezze che ho osservato in blocchi di studenti per cui cerco di prevenirle per l'anno dopo. di cui invece vi vorrei parlare, che sono più legati al senso di catturare le eccezioni, non alle regole che vi permettono, le regole ce le avete ben chiare, ma l'uso pratico, a cosa servono e perché, mi sembra che siano un pelino meno chiare.

Quindi, questo metodo qua. Supponiamo che... Io voglia, bella chiamata ricorsiva, forse è meglio di no, non complichiamoci inutilmente la vita.

Ah, perché non c'è? Così, se no uno più normale. e poi qua mi invento assolutamente a caso eccezioni che possano essere adesso supponiamo che io questa siccome Il mio metodo ha sollevato una null reference exception, che è una di quelle cose che ben difficilmente M, poverino, solleverà visto che prende un parametro di tipo intero, non so da dove se la possa prendere una null reference exception.

Ma facciamo finta che sia così e voglio gestire questa null reference exception. Che cosa vuol dire gestire? Gestire un'eccezione può voler dire varie cose. La prima è... la gestisco completamente quindi ho chiamato un metodo in questo caso ml lui ha scritto del codice questo codice ha sollevato un'eccezione io la catturo è una situazione erronea o particolare non è il flusso normale del mio algoritmo ma so assolutamente come risolvere la situazione quindi so che cosa fa faccio il catch e che sono e poi magari che cosa ho a disposizione cambio la c e poi magari qua fate conto che vado avanti e cambio continuo col mio codice dopo il block try catch vado avanti col mio codice è cambiato qualcosa si ho recuperato nulla exception So nella mia testa che quando c'è stata un null exception vuol dire che devo aumentare il valore di C e poi da lì in avanti il mio flusso logico continuerà esattamente nello stesso modo.

In molti casi non si riesce a fare questo, si riesce soltanto a fare una gestione parziale, cioè faccio qualcosa ma poi resto in una situazione che è erronea da cui non so come tirarmi fuori. L'esempio tipico è, nel mio codice si solleva un'eccezione, è un errore e io non so come uscire da questa situazione di errore. Però il mio codice faceva delle cose, ad esempio il mio codice è un inizializzatore, ho già iniziato a inizializzare degli elementi.

Siccome sono in una situazione di errore, devo fare l'handu di quello che ho fatto, quindi prima catturo l'eccezione. Faccio l'undo delle cose che ho fatto e poi ributto fuori l'eccezione e qualche santo sarà, chi mi chiama saprà che cosa fare. Però chi mi chiama non si trova in una situazione sporca in cui un po'di cose sono cambiate e un po'no perché io ho avuto l'errore a metà. Lascio a chi deve gestire questo errore l'inconvenza di farlo, ma in una situazione in cui il contesto è bello pulito. È come se io non avessi mai...

non avessi mai iniziato l'esecuzione tranne che sia stata sollevata l'eccezione. Quindi una cosa che capita molto spesso è fai qualche cosa e poi risollevi un'eccezione, la quale eccezione può avere lo stesso tipo o avere un altro tipo dell'eccezione che ho sollevato. Quindi supponete che sono nella situazione qua in cui voglio risollevare l'eccezione.

cambiandogli il tipo non è più un reference ad essere un argomento che so che sono che è stata sollevata questa perché in realtà l'argomento che mi è stato passato faceva schifo era un intero che ha fatto sì che siano stato generato questo errore benissimo allora tutte le eccezioni hanno vari costruttori, alcuni dei quali ci sono proprio sempre, ce n'è uno che è quello che prende soltanto il messaggio d'errore, uno che prende un messaggio d'errore e una inner e uno che prende, che non lo vedo, facciamo finta che ci siano solo questi due, poi perché questo è un argomento exception, quindi anche è un'eccezione che fa riferimento a un particolare argomento. Questi due costruttori vengono duplicati in un certo senso in un'altra coppia di costruttori che ha in più la stringa paranname. Quindi messaggio e paranname, messaggio, paranname e inner exception.

Quando è secondo voi che devo usare quella con la inner exception? Cioè in questo caso secondo voi devo usare uno di quelli con la inner exception sì o no? Chi è per il sì?

Chieperi no? Chieperi non ho capito un cacchio della domanda che mi avete appena fatto. Ok, riprovo da capo.

Qua devo applicare un costruttore, ok? Facciamo conto che... Cambio tipo di eccezione così magari è più facile. Ok, Arithmetic Exception, siccome non ha un argomento, non fa riferimento ad un argomento, ha soltanto i due costruttori di cui vi parlavo due.

Prima, uno, ci posso scrivere un messaggio, ok? E posso farla finita qua. Oppure qua posso mettere una bella virgola e metterci anche una inner exception. Secondo voi, devo farlo o ho finito lieva bene così?

Questa è la domanda. Quindi, chi è che pensa che non ci sia ragione di usare il costruttore che ha due parametri, quello con uno va bene, e invece chi è che pensa che sia... Molto meglio, non un pochino, molto meglio utilizzare quello con i due parametri.

Chi è per i due parametri? Chi è per un parametro? Applaudo l'unica persona che ha avuto il coraggio di dirlo, invece sono un attimino preoccupata del fatto che... La maggior parte della classe sembra persa.

Non capisco se siete persi, perché la domanda è troppo stupida. Ok, sapete perché le eccezioni hanno una inner exception? Riproviamo da capo, che era quello a cui volevo arrivare.

No, allora. Non so, vabbè scusate, ogni tanto ho dei momenti di sconforto. Allora, a cosa servono le eccezioni?

Le eccezioni servono a poter guidare l'esecuzione del codice, quindi non servono per gli esseri umani, servono per l'altro codice in generale. Quindi il codice che riceve un'eccezione sulla base del tipo dell'eccezione e eventualmente di alcuni valori dei membri dell'eccezione può decidere di fare una cosa piuttosto che l'altra. Ad esempio, supponete che io qua, se quella che ho ricevuto è un'aritmetic exception, ragionevolmente ci sarà scritto che diavolo di errore aritmetico è stato fatto, giusto?

Quindi, se io la passo come inner exception, visto che io non ci ho fatto niente, non l'ho gestita in nessuna maniera, quindi qua ci metto la mia brava E chi cattura la mia eccezione vede l'eccezione E e quindi se gli basta sapere che è stata sollevata una ah scusate, era un viceversa era una nulla non ce la posso fare, scusate quella che ho catturato era una nulla reference exception quindi non ho idea di quale senso, cioè quale ulteriore informazione ci possa essere dentro la null reference exception. Ma se quella contiene un'informazione, chi prende la mia eccezione, cioè l'arithmetic exception, guardando la sua inner, cioè quella, la null reference exception, può decidere di fare una cosa piuttosto che l'altra. Supponete ad esempio che il mio codice sollevi arithmetic exception in vari punti, perché cattura vari tipi di eccezione e a seconda di per quale ragione è stato sollevato Arithmetic Exception, chi usa il mio codice deve fare una cosa piuttosto che l'altra per uscire dalla situazione d'errore.

Come fa a saperlo? Beh, perché guarda qual è la inner, quindi il fatto di passare tutte le informazioni che sono arrivate fino a me, a chi chiama me, permette a chi mi chiama di avere tutto il quadro completo e di potersi quindi ricostruire tutto il viaggio di come siamo arrivati a quella situazione d'errore. Quindi la inner è sempre la... Sì, quindi tutte le volte che voi sollevate un'eccezione perché ne avete catturato un'altra, ci deve essere il parametro inner e deve essere quello, cioè deve essere proprio quella particolare eccezione. Quando è quindi che usate quello senza parametro inner?

Quando siete quelli che per la prima volta si accorgono di una situazione d'errore, quindi non perché un altro venga scoppiato del codice in faccia, ma perché avete guardato i parametri e un parametro doveva essere un numero pari non è un numero pari, quindi siete voi che avete fatto il controllo e avete deciso la cosa non va bene, sollevo argument exception. Quando siete in questa situazione ovviamente non avete nulla da passare come inner, perché siete la radice dell'errore, ma tutte le volte che siete uno dei passi intermedi, quindi qualcun altro ha fatto un errore, voi lo gestite un po'parzialmente e lo ripassate in su, in tutti questi casi la inner ci deve essere e deve essere quello che avevate catturato. Errori classici che non vanno fatti.

Infatti sono, non questa, invece di fare questa, faccio, che adesso si arrabbierà giustamente perché due throw uno sotto l'altro non hanno senso, molti capiscono che propagare l'errore non è propagare l'eccezione, ma è propagare... il messaggio d'errore dell'eccezione che ho catturato. Quindi a me è arrivata un'eccezione che mi ha detto è scopiato un disastro perché le cose...

non ho trovato la referenza, era nulla. E invece di passare a un altro, il fatto che c'è un'eccezione che è una null reference, gli dico come messaggio d'errore è scopiato un disastro perché ho trovato un'eccezione che era nulla, una referenza che era nulla. E sto facendo due cose che non vanno. la prima è che gli sto facendo credere che sono io che ho trovato l'eccezione ok? perché se io gli passo la inner e dentro alla inner c'è anche tutto lo stack di chiamata quindi sa che cosa, sa chi è che ha generato quella, ma se io gliela tiro via e gli do soltanto il messaggio d'errore legge lo stesso messaggio d'errore ma non sa più chi è che l'ha originato, ovvero lo sa ed è questa riga di codice, mentre non è vero, quello che ha generato questo In origine il problema non è questa riga di codice, è qualcosa che sta qua su dentro al try.

Il secondo problema è che com'è che faccio a gestire in automatico una cosa se quello che mi esce fuori, cioè se l'informazione del tipo di errore sta dentro al messaggio? Che cosa devo fare? Oltre a prendere l'ascia e andare da quello che ha creato la situazione. Se io devo gestire degli errori sulla base dei messaggi d'errore, devo farmi il parsing dei messaggi d'errore, giusto? E basta che uno abbia fatto un typo mentre scriveva il messaggio d'errore e non funzionerà, e basta che il codice l'abbia scritto uno sloveno, e il mio codice che è scritto da un italiano non lo riuscirà mai a capire che cosa diavolo è successo come situazione d'errore.

Cioè, usare i messaggi d'errore come meccanismo per la comunicazione. da macchina a macchina è di una stupidità abissale, perché veramente non ha senso. I messaggi d'errore sono per gli esseri umani, sono per noi quando facciamo dei bug del codice che ci aiutano a dire guarda che è successo un casino e secondo me il casino è questo. Non servono al codice chiamante perché sulla base del messaggio d'errore fa una cosa piuttosto che l'altra.

Il codice chiamante può cambiare sulla base del tipo dell'eccezione. di un valore di un campo dell'eccezione, di qual è il tipo della inner, perché? Perché è uno dei valori dei campi, ma sul valore della stringa è un delirio, altro che artificial intelligence ci vuole per riuscire a gestire una cosa sulla base dei messaggi d'errore. Quindi, morale della favola, quando catturate un'eccezione, la gestite parzialmente e sollevate una nuova eccezione, dovete sempre, cioè la cosa sensata è sempre il fatto di mettere, usare il parametro inner per propagare l'eccezione che avete catturato.

Adesso, se io riuscisse a eseguire questo codice, vi vorrei far vedere cosa succede, perché... Un buon modo su di software per scrivere un messaggio di errore... Anche come messaggio a livello futuro diciamo. Il messaggio lo stai scrivendo per il programmatore, ragionevolmente. Quindi, dovrebbe essere informativo, esattamente come i commenti nel codice.

Quindi, non deve essere inutilmente prolisso, non deve dire cose che già so. Se sto prendendo un arithmetic exception, vuol dire che c'è stato un errore aritmetico. Oppure che sei un idiota che ha usato arithmetic exception per una cosa che non c'entrava veramente niente. Quindi, mettere nel messaggio...

è successo un casino aritmetico non mi aiuta niente mentre il divisione per 0 perché il parametro x era 0 quella mi aiuta perché so qual è il tipo di errore e so dove andarlo a cercare questo qua si chiama m sto cercando di farvi vedere cosa succede quando eseguo così vedete a cosa serve aver messo l'excel l'inner per la qualcosa spero di avere una console da qualche parte non mi ricordo più E qua pubblica sì? Ok, ce l'ho, sì. Ma perché? Mi sono già persa, era M?

Mi gioco l'aiuto da casa, il metodo si chiamava M? No, era 4. Quindi devo chiamare... mm quello che solleva l'eccezione ma quello che la cattura è mai bull metodo che è un forse se lo mettessimo pubblico potrebbe aiutarci Siamo qua.

già che ci siamo tanto vedete col break point così l'esecuzione arriverà fino a qua che non è che ci sia molto da fare ma partiamo ok mi sono fermata avendomi sul break poi mi sono fermata lì con f10 passare alla riga dopo con f11 entro dentro la chiamata E sempre perché ho bisogno della badante è la prima volta che vediamo il debugger. Sì. Ok, quindi questo è il momento di... vedere che cosa ne ha tirato fuori.

Allora, il debugger simpaticamente vi offre tutta una serie di informazioni utili, molte delle quali a me passano personalmente sopra la testa perché non sono sufficientemente brava da capire che cosa fanno. Nella finestra dei tool diagnostici vedete che cosa sta succedendo, quindi gli eventi che sono stati sollevati, quanto memoria sta occupando il processo, quanta CPU, ok? e qui se guardate gli eventi vedete quali sono gli eventi che sono effettivamente stati, sono successi.

Qua ci serve poco, sono eventi poco interessanti, ho preso il breakpoint, quindi è arrivato sul breakpoint e sono entrata in uno passo di esecuzione del metodo. Quando faremo l'entity framework e vi interfaccerete con le basi di dati, lì ci troverete tutti gli eventi di comunicazione con la base di dati, quindi sarà molto più interessante come cosa. Qua di sotto sono le cose che uso più spesso, qua avete il call stack, cioè che cosa c'è, qual è la pila delle cose che sono in esecuzione.

Vedete abbiamo il main, il main ha chiamato il myBullMethod e quindi questa è la pila delle cose che sono in esecuzione e la freccina gialla vi dice dove siamo, siamo in esecuzione su quello lì. Nella finestra qua di sinistra avete due tab di solito. questa è sempre la configurazione di default quindi se non avete cambiato ve la trovate così ovviamente potete modificare spostare i tab fare tutto ma questo dovreste riuscire a trovarlo facilmente locals vi dà il valore di tutte le variabili in questo momento quelle che sono locali a dove siamo quindi il dis è l'oggetto di c su cui io sto facendo le cose siccome ho chiamato il costruttore senza parametri x1 x2 x3 non sono stati ci sono stati inseriti col valore di default e quindi sono tutti e 3 0 il parametro a su cui ho fatto la chiamata è 42 vado a vedere perché non me lo ricordo è probabile sia 40 poi l'altra finestrella che è la watch qua potete scrivere una qualunque espressione a vostro piacere e vi aggiorna che cosa qual è il valore di quell'espressione quindi vi permette in tempo reale di vedere che cosa sta succedendo In realtà vi permette di fare cose anche più acrobatiche, tipo questa, potete cambiargli sotto i piedi i valori di uno dei campi.

Vedete che per un attimo è rosso, il rosso vi dice che cosa è cambiato in questo passo di esecuzione rispetto a prima. Questo non è un passo di esecuzione del programma, è un passo di esecuzione mio del debugger in cui io sono andata a cambiare i valori. Vi può servire il fatto di cambiare i valori? Sì, nel senso che supponete di essere, state programmando, vi aspettate che succeda qualche cosa, non succede. Ok, andate in modo debug.

Riga per riga e dite, oh caspita, io qua in questo punto del programma mi aspettavo che un certo campo fosse positivo, invece vale meno 42. Sarà l'errore, quindi c'è sicuramente un errore per cui lì il valore non è positivo ed è meno 42. Però può darsi che se anche fosse stato positivo poi ci sarebbe stato un altro errore più a valle, giusto? Quindi ci metto un valore positivo e vado avanti con l'esecuzione. in questa maniera in un'unica passata di debug posso sperare di beccare due errori o capire che effettivamente l'unico errore che c'è è quello che mi ha portato a pensare che ci fosse una cosa positiva e invece c'era un valore negativo quindi può essere che funzioni non sono tantissimi casi nella maggior parte dei casi cambiare i valori dei parametri è bello ma non vi serve particolarmente torniamo a noi, sono qua vado con F10 sulla riga sotto, ok, di nuovo chiamata di metodo entro nella chiamata F11 Vedete che i locals adesso cambiano perché adesso ho anche la C, non ho soltanto, ho come locals tutte le cose del dis, tutte le cose del metodo esterno che è la A, perché le vedo, perché questo è un metodo locale, più il parametro del metodo interno.

Quindi nei locals vi trovate sempre tutte le cose che sono in scope nella riga dove siete. Cambio il valore della A, vedete è diventato rosso. Perché?

Perché l'ho incrementato e quindi avendo eseguito A più uguale C, è cambiato il valore di A e mi segna nella finestra le cose che cambiano. Questo è molto comodo quando andate riga dopo riga, se siete interessati a vedere cosa succede a qualche cosa, intanto che non diventa rosso potete andare avanti abbastanza tranquillamente. Sono qua, F11.

sono qua, finalmente sollevo l'eccezione. Siccome sono in modalità debug, mi trovo questa qua che mi dice attenzione, è stata sollevata un'eccezione che non è gestita in questo particolare punto, che esiste null reference exception con messaggio fake. Benissimo.

Nell'exception settings io avevo scettato di fermarsi quando questa eccezione viene sollevata. posso mettere una eccezione a questa regola e dire no vai avanti ma comunque non mi interessa più di tanto voglio andare avanti ci riesco e sono andata avanti e sono arrivata al catch ok vedete che adesso scusate mi sono dimenticata di farlo notare prima nella col stack qua Siccome sono dentro un metodo, che dentro un metodo, che dentro un metodo, la call stack è cresciuta e man mano mi ci sono appilate gli altri metodi. Scrivo a console, null exception is expected, ok.

Cambio, benissimo. Adesso ho sollevato la mia nuova eccezione. La quale nuova eccezione, se io riuscissi a allargare la finestra ci sarebbe una chance di vederci, questo mi permette di vedere qual è l'eccezione che viene, la nuova eccezione che viene sollevata. Vedete che la nuova eccezione che viene sollevata al messaggio che ci avevo messo, non so, ma fra le varie cose ha una inner exception in cui il messaggio era fake e qua mi dà tutte le informazioni che avevo prima.

sulla eccezione che ho sollevato in particolare mi dà lo stack trace lo stack trace questo è lo stack trace della inner exception mentre questo è lo stack trace mio di nuovo lo stack trace mio lo stack trace mio è come me lo aspettavo cioè c'ho il main che ha chiamato il myboolmethod che ha chiamato il metodo interno questa è la mia ne ha tre ok se vado nella inner spero questa ne ha due Perché? Perché la inner è stata sollevata direttamente dal metodo, non mi ricordo più come si chiama, MyBullMethod, no, MM, ok? Cioè MM ha sollevato l'eccezione quando è stato chiamato da MyBullMethod. Io ho sollevato la mia eccezione dopo e quindi sono a un livello di annidamento superiore.

Perciò il fatto di passare la inner exception permette a chi fa debugging di capire qual è il percorso che ha generato l'errore. Questa è la ragione dal punto di vista della comunicazione umana per cui è importante passare la inner exception. Dal punto di vista invece del codice è il fatto che posso andare a esplorare come è fatta questa inner exception a seconda di come è fatta eseguire in un modo o eseguire nell'altro.

Di nuovo, quando arriveremo all'entity framework, una delle cose classiche è che riceverete delle eccezioni dalla base di dati. È un fatto della vita ed è giusto così. Ci sono una serie di cose che solo la base di dati può controllare, inutile che cerchiate di farlo da codice, quindi passate la palla alla base di dati, la base di dati si tira i suoi conti e vi risponde, vi risponde con un'eccezione. Simpaticamente, l'eccezione che arriva su... Non ha nessuna informazione su qual è l'errore a livello della base di dati.

È soltanto un'eccezione che vi dice, eh, parlando con la base di dati, c'è stato un casino. Grazie. Ma contiene una inner, che contiene una inner, che contiene una inner a catena, l'ultima delle quali è quella che veramente è stata sollevata dalla base di dati.

In quella c'è un codice d'errore. Il codice d'errore vi dice veramente qual è l'errore. Quindi questa cosa che vi ho fatto vedere qua, Ve la troverete da fare sicuramente all'interno del progetto.

Il fatto di catturare un'eccezione, guardo qual è la sua inner, cerco e sulla base dei campi della inner decido come andare avanti col mio codice, perché a seconda del tipo d'errore solleverete di solito tipi di eccezioni diverse oppure non solleverete affatto nessuna eccezione. E se adesso vado avanti, è finita l'esecuzione, chiaramente. che mi dice, spero, sì, che c'è una handle exception di tipo arithmetic exception eccetera.

Caso particolare in cui di gestione parziale delle eccezioni è quando risollevate un'eccezione dello stesso tipo. Giusto, cioè ci ho fatto qualche cosa ma poi il tipo di eccezione mi andava benissimo, cioè qua io ho cambiato il tipo da null reference exception a arithmetic exception, invece mi va bene, ci ho fatto un po'di cosine ma è inutile, vorrei risollevare la stessa eccezione. Qualcuno fa così, qualcuno fa così e sono tutti e due non sensati. dice stai risollevando un'eccezione, forse non è proprio quello che volevi, in effetti di solito no, quello che volevo fare era questo e basta stro fa esattamente risolleva l'eccezione che ho catturato senza cambiarla in nulla quindi non cambia i parametri non cambia lo stack trace, passa così com'è questa di sotto È come prima, quindi crea una nuova eccezione che ha una inner che è la E, non risolleva la E. Quindi la persona che si trova questa eccezione, a catturare questa eccezione, spacchetta l'eccezione, trova la E originale che è esattamente con la stessa informazione, la spacchetta e va avanti.

Quindi avete soltanto aggiunto un livello di indirezione per far diventare matto quello che gestisce il codice, niente di più. quindi anche questa è mai fino a qua tutte cose che avreste dovuto già sapere avere più o meno presenti, le abbiamo riviste così si sono un po'sistematizzate, però non vi sto dicendo nulla che sia specifico di C-Sharp rispetto alla gestione delle eccezioni. Invece effettivamente C-Sharp ha qualcosa di particolare, la cui sintassi vado a vedere perché non me la ricordo mai. ok e when cioè invece di catturare un'eccezione potete catturarla soltanto quando quell'eccezione soddisfa qualche condizione faccio un altro catch che così o qualcosa di più utilizzabile Allora, supponete di avere catturato un argument exception a il nome del parametro a cui fa riferimento. Adesso qua, ho aggiunto un parametro col valore di default, quindi se lo metto nella chiamata ci posso mettere quello che voglio, ma posso ometterlo.

Ne riparleremo dopo, ve lo volevo solo dire per non generare panico in questo momento. Allora, qua supponiamo che questa eccezione possa fare riferimento, peccato che l'abbiamo messo nel posto sbagliato, perché quello che sollevava l'eccezione era mm, quindi è mm che mi deve avere il secondo parametro. Quindi, assunto delle puntate precedenti, M ha due parametri che sono W e B, e in questo mio esempio del tutto fittizio, sollevo un argomento exception a causa del valore di W.

Quando qua la catturo, può venire ragionevolmente perché è W che è la cosa che ha generato il parametro, o perché è B. supponete di dire beh se lo fa w voglio farci qualcosa se invece il parametro che non va bene è b non so che cosa farci com'è che avrei potuto come che posso farlo con gli strumenti che conoscete finora con un if qui se appunto rami è doppio faccio qualche cosa altrimenti la risollevo questo funziona quindi se il parametro è MW farò del codice qua dentro qualche cosa che manca come gestione ma non importa altrimenti risollevo l'eccezione perché perché non ci potevo fare rigorosamente niente ci metto del codice a caso questa è una situazione relativamente comune nel senso a seconda del valore della vostra eccezione cioè a seconda del perché è stata No, riprovo da K. In un momento, in teoria, quando la gestione delle eccezioni dovrebbe basarsi tutta soltanto sui tipi.

Cioè, dovrebbe essere che se un codice solleva un certo tipo di eccezione è perché c'è stato quel particolare errore e quindi soltanto sul tipo dell'eccezione io so che cosa fare. Nella realtà dei fatti può darsi che quel tipo di eccezione derivi da varie situazioni erronee nello stesso pezzo di codice. Potrei risolvermela sempre basandomi soltanto sul tipo? Certo che sì, basterebbe complicare la gerarchia delle eccezioni.

Potrei avere un argument exception W e un argument exception, non mi ricordo l'altro parametro come si chiamava, A? Argument exception A. Quindi, avere due figli di argument exception uno per la A e uno per il W sollevare in un caso quello con l'A e nell'altro quello con il W come vi potete immaginare questo porterebbe ad avere delle gerarchie di eccezioni con migliaia di diversi casi possibili sarebbe assolutamente inutilizzabile quindi che cosa faccio?

beh ci sono dei casi in cui veramente il valore che c'è dentro cioè aggiungo un parametro aggiungo un campo alla mia eccezione e quindi la gestione dell'errore dipenderà non più non solo dal tipo dell'eccezione ma anche dal valore di quel parametro. Questo è il caso, ok? Se il parametro è a faccio qualcosa, se il parametro è w faccio qualcos'altro. Ok, siccome questo è molto comune, è molto comune questa situazione in cui ci sono dei casi in cui so cosa fare e ci sono degli altri casi in cui non so che cosa fare, quindi capita abbastanza spesso per un tot di casi ok, per un tot altro rifaccio il throw. Allora invece di fare questa Esattamente in maniera equivalente posso usare un filtro.

Tonde, traffe, buffi. e qua ci metto soltanto il codice mi serve, magari senza le cose. Allora che cosa fa questo comando?

È un filtro. Quando la condizione booleana che sta dentro al WEN è vera, il catch si attiva e la licenzione viene catchata e quindi viene eseguito il codice che c'è dentro al blocco catch. Quando il filtro dà come valore falso, il catch non si applica.

È diverso rispetto a un'unica differenza, però è abbastanza fine rispetto al codice che avevamo prima, quello senza filtro e con l'if dentro al catch. che è il fatto che se fate il catch e fate throw nella lista delle cose che sono successe, questo fenomeno resta. Se fate il filtro e il filtro è falso, non avete fatto il catch e quindi non resta il fatto che avete fatto un catch e un throw, cioè la lista degli statement resta più corta.

Di nuovo è più economico e si legge un pochino meglio, però veramente è una finezza. che vi potete dimenticare, era solo per dirvi che esiste una differenza, sì, se questo è il tipo di cose che vi piacciono, non sono la persona giusta a cui chiedere la prova finale, ma vi so dire a chi, ma sono cose molto particolari, sono proprio da persone che amano i linguaggi. Tornando qua... Questo filtro parte così e va bene. In realtà possiamo migliorarlo.

Qua dentro al filtro ci potete mettere una qualunque espressione booleana. In particolare potete definirvi un metodo che ha di valore booleani, che fa qualcosa. Quindi invece di fare questo, posso metterci una chiamata di metodo. Qual è l'intima bellezza del poterci mettere una chiamata di metodo?

Che potete avere un metodo. che fa la cosa che deve fare, cioè se vi trovate la situazione in cui, supponete che anche qua ci sia un altro throw, pensate di essere in questa situazione, sempre l'eccezione non deve essere catturata, se il parametro era W potevo farci qualcosa, se il parametro è l'altro non so che cosa farci, ma in ogni caso l'eccezione deve andare avanti. Com'è che posso gestire questa cosa?

Posso gestirla, sperando di arrivare a scrivere nel posto giusto, qua forse. allora cos'è che è cambiato rispetto a prima il filtro si applicerà mai il cache verrà mai eseguito ovviamente no ok perché il filtro restituisce sempre falso quindi la valutazione di una chiamata di myfilter non ci sono santi mi restituisce falso quindi il filtro fa sì che il cache non abbia mai non ci sia mai non abbia non abbia non possa mai essere eseguito in compenso la gestione che avevo ce l'ho già dentro al filtro come side effetti quindi faccio dentro al filtro tutte le cose che voglio che succedano e poi restituisco sempre falso oppure se invece c'è il caso in cui questo non ci fosse in queste istruzioni di troppo non ci fosse c'è il caso precedente qua avrei fatto se è w faccio questo costituisco falso e dentro qua avrei di nuovo un troppo. Insomma, a seconda di che cosa volete fare, si può fare. Se avete dei dubbi sulle eccezioni, questo potrebbe essere un bel momento per sollevarli. Ah sì, uno degli usi tipici di questo meccanismo col filtro è quando volete fare logging.

Quindi volete che le eccezioni passino, che non siano intercettate, che sia come se non ci fosse stati, ma al tempo stesso volete scrivere su un file tutti i messaggi d'errore di tutte le eccezioni che sono state sollevate. tutti gli stack trace, tutto quello che volete il filtro che cosa fa? restituisce sempre falso e fa il login sul file che vi serve questo è uno degli esempi classici è veramente comodo ne vedrete un uso abbastanza estensivo Mi sembra che manchino più soltanto, sì, manca più soltanto una cosa che sono le costanti.

Allora, qua forse è più semplice se passo un attimo soltanto alla... Scusate, ho un attimo di preoccupazione su che cosa sta registrando e non lo saprò mai perché, data la riconsidità della cosa, credo di stare catturando lo schermo mio, questo, ma tanto non c'è niente di privato e va bene lo stesso. Allora, quando... Parliamo di costanti, in Java che cosa succede?

Cominciamo a monte. Perché servono le costanti? Perché, ricordatevi, il principio è sempre lo stesso. Quando scrivete del codice, cercate di obbligare le persone che useranno il vostro codice a usarlo come voi lo avete pensato. Quindi, se voi pensate che un qualche cosa non debba cambiare, dichiaratelo come costante.

In questa maniera, se qualcuno cerca di cambiarlo in primis voi stessi, l'errore ce l'avete a tempo di compilazione, invece di avere uno scuro errore a livello di esecuzione una volta ogni 47. Quindi, tutte le volte che potete, blindate sempre in tutti i modi possibili il vostro codice. Com'è che si fa a dichiarare una cosa costante dentro Java? Final static è quindi...

Se l'avete dichiarato così, non può essere modificato in nessuna forma e maniera. La semantica che c'è dietro però in Java è abbastanza particolare, nel senso che sicuramente funziona dal punto di vista di essere statico, è statico nel senso di essere costante, nel senso che non può essere modificato, è sempre vero. Però se l'oggetto...

che state dicendo che è costante, è un oggetto diciamo complicato, è un oggetto che non è noto a tempo di compilazione, la semantica è che vi dà un errore se cercate di modificarlo e quindi non riuscite a compilare il codice, però dietro l'oggetto esiste. Invece, se è una cosa, è una costante nota a tempo di compilazione, allora risparmia di costruire questa... di allocare la memoria per l'oggetto che tanto non potrete mai modificare e fa in line, cioè prende il valore di quell'espressione e lo butta in tutte le occorrenze della costante vengono sostituite con direttamente il valore dell'espressione in C sharp hanno separato queste due cose hanno messo due costrutti diversi Uno è il read-only, il read-only è esattamente analogo al final, cioè una cosa che non può essere modificata però esiste, esiste come oggetto, esiste come campo, semplicemente è un errore statico cercare di cambiare nel valore.

const invece lo potete utilizzare soltanto con le cose che effettivamente sono costanti a tempo di compilazione e in questo caso viene fatto l'inline, cioè viene sostituito ogni occorrenza della costante col valore di quella costante. Quale valore? Quello calcolato al tempo di compilazione. Se è calcolato al tempo di compilazione non è possibile che sia diverso in oggetti diversi. perché gli oggetti non ce li avete ancora a tempo di compilazione.

Deve essere un'espressione che vale per qualunque oggetto di quella classe che venga costruita. Quindi, siccome è sempre lo stesso, la costante non è mai una cosa di istanza, è sempre statica perché non può essere diversamente, perché è un valore che è uguale per tutti gli elementi della classe e no perché è noto al tempo di compilazione. sono adesso ho un attimo solo di balletto c'è ancora circa un quarto d'ora in cui inizio brillantemente il prossimo argomento che è sempre codice per farlo però ho bisogno un attimo di cambiare la modalità di visualizzazione quindi andrà tutto non voglio dire dove si, slideshow, proprio quello, grazie ok e credo che sia meglio