C# e Visual studio di Alessio Cislaghi
←
→
Trascrizione del contenuto della pagina
Se il tuo browser non visualizza correttamente la pagina, ti preghiamo di leggere il contenuto della pagina quaggiù
INTRODUZIONE In questo fascicolo si tratteranno gli argomenti riguardanti: l’approccio al mondo della programmazione in particolare attraverso il linguaggio di programmazione C# e l’ambiente di sviluppo Visual Studio. Ho cercato di sviluppare una semplice guida per introdurre tutti al mondo della programmazione in C#, spero che possa essere di aiuto per chiunque prenda visione di questo fascicolo. 2
INDICE C# 7 in ambiente di sviluppo Visual Studio 2017………………………………...5 1.1 Proprietà di Base………………………………………………………...5 .Lenght……………………………………………………………….6 .Trim / .TrimStart / .TrimEnd………………………………………..6 .Replace……………………………………………………………...6 .ToUpper / .ToLower………………………………………………...6 .Contains…………….………………………………………………6 .StartsWith / EndWith………………………………………………..6 1.2 Funzioni matematiche…………………………………………………...6 1.3 Variabili….……………………………………………………………….7 1.4 Rami e cicli……………………………………………………………….7 If …………………………………………………………………….7 Else…………………………………………………………………..7 While…………………………………………………………………7 For…………………………………………………………………...7 1.5 Gli operatori……………………………………………………………8 1.6 Auto-incremento ed Auto-decremento di una variabile………………8 Var++ ……………………………………………………………….8 Var--…………………………………………………………………8 ++Var………………………………………………………………..8 --Var…………………………………………………………………9 1.7 Array……………………………………………………………………..9 1.8 Istruzione foreach……………………………………………………….9 for oppure foreach…………………………………………………...10 1.9 Classificazione a classi………………..………………………………..10 Incapsulamento……………………………………………………...10 3
Accessibilità………………………………………………………....11 Polimorfismo………………………………………………11 Ereditarietà………………………………………………...11 Costruttore…………………………………………………………..11 Overload di costruttori………………………………………………12 Metodi Try e Chatch…………………………………………………12 Generare eccezioni…………………………………………………..12 Metodi e dati statici………………………………………………….12 1.10 Copia di variabili e classi………………………………………………13 1.11 Parametri……………….………………………………………………13 ref…...……………………………………………………………….13 out……………………………………………………………………13 1.12 Stack ed Heap………….……………………………………………….14 1.13 Boxing ed Unboxing……………………………………………………14 boxing………………………………………………………………..14 unboxing……………………………………………………………..14 1.14 Enumerazioni…………………………………………………………..14 1.15 Tipi di struttura………………………………………………………..14 1.16 Differenze tra strutture e classi……………………………………….15 1.17 Copia delle variabili di struttura……………………………………...15 1.18 Equivalenza tra parola chiave e tipo………………………………….16 1.19 Classe System.Array…………………………………………………...16 1.20 Definizione di classi collection…………………………………………16 1.21 ArrayList……………………………………………………………….16 1.22 Queue………………………………………………………………...…17 1.23 Stack……………………………….……………………………………17 1.24 SortedList………………………………………………………………17 1.25 Ereditarietà…………………………………………………………….17 1.26 Chiamata dei costruttori di una classe base………………………….18 1.27 Metodi New……………………………………………………………..18 1.28 Metodi virtuali…………………………………………………………18 1.29 Metodi Override……………….………………………………………18 1.30 Regole metodi virtual ed override……………………..……………...18 1.31 Accesso protetto………………………………………………………..19 1.32 Interfacce………………………….……………………………………19 4
C# 7 in ambiente di sviluppo Visual Studio 2017 In questo capitolo verranno spiegati gli argomenti di base che riguardano la programmazione in C#. Per iniziare a programmare si deve prima conoscere l’ambito in cui si sta operando; .Net è una piattaforma (Framework) per lo sviluppo di software che comprende una libreria di oggetti di base che sono utilizzabili per creare un programma. Un obiettivo di un programmatore deve essere quello di riuscire a generare dei codici “puliti” ciò significa implementare la capacità di scrivere un programma nel modo più chiaro e meno fraintendibile possibile, oltre a evitare di scrivere troppe righe di codice scegliendo il metodo migliore. Innanzitutto vorrei dare una definizione di tre componenti essenziali di un programma in C#: la variabile è un dato che viene creato nella memoria del programma al momento della sua creazione, successivamente questo dato prende forma quando alla variabile viene assegnato un valore; la stringa è un’ istruzione che svolge un’azione all’interno di un codice, le stringe possono essere molto diverse tra loro, infatti possono assegnare valori alle variabili, generare un ciclo, inserire un immagine, ecc. La classe è lo spazio in cui possono essere definite le variabili e dove vengono utilizzati i cicli e si svolgono le azioni principali del programma. 1.1 Proprietà di base Nel mondo della programmazione esistono diverse proprietà che permettono di ricavare o modificare le caratteristiche delle stringhe e si esprimono mettendo un punto e poi il nome della proprietà. 5
.Length Permette di ricavare come output la lunghezza della stringa che legge, nell’esempio: es. string PrimoAmico= “Maria”; string SecondoAmico = “Luca”; Console.WriteLine ($”I miei amici sono{PrimoAmico} e {SecondoAmico}.”); Console.WriteLine ($”Il nome {PrimoAmico} ha {PrimoAmico.Lenght} lettere.”); Console.WriteLine ($”Il nome {SecondoAmico} ha {SecondoAmico.Lenght} lettere.”); il risultato di questa parte di codice sarà: I mie amici sono Maria e Luca. Il nome Maria ha 5 lettere. Il nome Luca ha 4 lettere. .Trim / .TrimStart / .TrimEnd Permette di rimuovere gli spazi vuoti indesiderati all’interno di una stringa. .Replace Permette di sostituire il testo di una stringa modificando solamente la parte di stringa che viene richiesta con una chiave. .ToUpper / .ToLower Permette di sostituire il carattere maiuscolo o minuscolo del testo di una stringa. .Contains Permette di verificare se una chiave è presente nel testo di una sottostringa, nell’esempio: .StartsWith / .EndWith Permette di verificare se il testo di una sottostringa inizia o termina con una chiave. 1.2 Funzioni matematiche Nella stesura di un codice si possono usare funzioni matematiche come addizione, sottrazione, divisione, moltiplicazione (+, -, /, *). Inoltre vi è anche la funzione resto che esegue una divisione ma tiene in considerazione come risultato solamente il resto; il suo simbolo è %. 6
1.3 Variabili Le variabili possono essere definite come INT se sono numeri interi sia positivi che negativi, DOUBLE se sono numeri che hanno cifre decimali, STRING se è una stringa di testo, DECIMAL se sono numeri che hanno molte cifre decimali. Variabili INT STRING DOUBLE 1.4 Rami e Cicli • If Il ciclo if esegue una o piu istruzioni se la condizione è verificata. Inoltre le condizioni del ciclo if possono essere più di una, nel caso si voglia che entrambe siano verificate si scrive && tra una condizione e l’altra, mentre nel caso si voglia che almeno una delle due sia verificata si scrive | | tra una condizione e l’altra. • Else Il ciclo else è in pratica l’alternativa al ciclo if, ossia, se la condizione imposta dal ciclo if non è verificata allora si eseguiranno le istruzioni del ciclo else. • While Il cilo while esegue un’istruzione finchè la condizione imposta è verificata. • For Il ciclo for è come il ciclo while con una differenza di sintassi. 7
1.5 Gli operatori In C# per eseguire operazioni matematiche esistono dei simboli standard: OPERATORI DESCRIZIONE + Somma - Differenza ++ Incremento -- Decremento ! Negazione logica * Moltiplicazione / Divisione % Resto intero > Maggiore di < Minore di == Uguale a != Diverso da >= Maggiore o uguale a
int esito = ++contatore; In questo caso viene assegnato il valore 4 sia alla variabile esito che alla variabile contatore. --Var int contatore = 3; int esito = --contatore; In questo caso viene assegnato il valore 2 sia alla variabile esito che alla variabile contatore. 1.7 Array Un array è uno spazio nella memoria costituito da “caselle” alle quali viene assegnato un valore, può essere visto anche come una matrice. Queste caselle rimangono vuote fino a che ad esse non viene assegnato un valore; che può essere definito in due modi: • Definendo ogni singolo valore di ogni cella • Definendo in una sola stringa tutti i valori Un array può contentenere anche valori non int, come string, double, ecc. In questo caso basterà sostituire i riferimenti int con il tipo desiderato e modificare i valori in base al tipo ( int = 9, string = “ciao”, double = 0.99, ecc. ). 1.8 Istruzione foreach Nella funzione “foreach”: si dichiara il valore di pin che è il primo della matrice, che incrementerà spostandosi di una casella ogni volta che si attraverserà la funzione, poi scrive il valore e ripete finche non verranno scritti tutti i valori presenti nell’array pins, questa dunzione è molto comoda se si deve eseguire un ciclo ripetitivo, cioè ripetere più di una volta lo stesso comando. 9
for oppure foreach • Nel caso si voglia prendere in considerazione solo la prima metà di una matrice ( o la seconda ) oppure non si voglia considerare per esempio il terzo valore è meglio utilizzare l’istruzione for. • L’istruzione foreach esegue sempre un’iterazione dall’indice di valore 0 all’indice di valore N - 1 ( dove N è il numero totale degli indici ); se si volesse partire dall’indice N - 1 ed arrivare a 0 si deve utilizzare l’istruzione for. • Se per l’esecuzione si necessita dell’indice e non solamente del valore di quest’ultimo si deve usare l’istruzione for. • Se si deve solo leggere i valori della matrice si usa l’istruzione foreach. • Se si deve modificare i valori della matrice si necessita dell’istruzione for. 1.9 Classificazione e classi La parola automobile classifica tutti gli oggetti che condividono lo stesso comportamento. Automobile Comportamenti Attributi Sterzata Volante Frenata Motore Accelerata Freni Le caratteristiche principali di una classe sono: L’incapsulamento - il polimorfismo - l'ereditarietà. Incapsulamento E’ un concetto tramite il quale una classe consente di assumere dati e tutte le funzioni che li gestiscono. Ha la possibilità di nascondere questi elementi al di fuori della classe. Le classi hanno dei meccanismi tali da rendere utilizzabili questi dati senza che l'utente sia a conoscenza della struttura dei dati stessi. Il codice del programma non sarà in grado di accedere ai dati della classe. Una classe avrà al suo interno dei metodi per renderli disponibili. Così facendo, si potrà modificare liberamente la struttura senza che il codice del programma ne subisca conseguenze. 10
Accessibilità Il metodo però, deve essere ulteriormente definito, ossia deve essere specificato se quest’ultimo è privato (se accessibile solo dall’interno della classe ) oppure pubblico ( accessibile sia dell’interno che dall’esterno della classe ). Polimorfismo E’ la capacità di assumere molte forme. L'argomento tra parentesi graffe {0}, si riferisce alla variabile che viene scritta dopo quest’ultimo separati da una virgola. Ma il metodo non sa di che tipo è la variabile che deve stampare. Il metodo in questione è polimorfico cioè si adatta alla maggior parte dei tipi che gli vengono passati. Lo stesso metodo può avere più di una variabile da stampare, ma questo non comporterà dei problemi proprio perché è polimorfico. Ereditarietà E’ la possibilità di creare una classe che eredita le caratteristiche da un’altra classe espandendone le funzionalità. Per esempio si può creare una classe generale Autoveicoli che raggruppa tutti i veicoli che hanno in comune alcune proprietà e funzionalità. Fatto ciò, si crei una classe Autovettura che eredita le proprietà e funzionalità comuni e in più si può aggiungere proprietà e funzionalità tipiche di un'autovettura, per esempio marca, modello, motorizzazione, ecc. . E’ stata quindi creato una classe che ha ereditato le funzionalità dalla classe “genitore” e ne abbiamo espanso le funzionalità aggiungendone di nuove non presenti nella classe “genitore”. L'ereditarietà consente di creare oggetti (classi) molto complessi e pieni di funzionalità. Costruttore Un costruttore non è altro che un tipo particolare di metodo, il quale, come dice la parola, “costruisce” uno spazio nella memoria dedicato ad esso. Quando si definisce una classe nella memoria si deve generare uno spazio di assegnazione, quindi nel codice si scrive: es. Cerchio C; c = new Cerchio ( ); Nell’esempio la parola chiave “new” serve ad assegnare C ad un oggetto anche dopo la propria dichiarazione. Infatti quando si scrive new si immette nella memoria uno spazio concreto, che prima, nella sola definizione non era presente 11
Overload di costruttori Cerchio C = new Cerchio ( ); Console.WriteLine(C.Area()); In questo modo però l’area degli oggetti Cerchio sarà uguale a 0. Il costruttore impostai valori a 0 e quindi il metodo “Area” della classe C fornirà un risultato pari a 0. A questo punto, visto che il costruttore è solo un tipo speciale di metodo, si assegna al costruttore il valore di “Raggio” come parametro. Di conseguenza verrà scritta una stringa che definirà il metodo Area ed in base al valore di Raggio fornirà il risultato. Metodi Try e Catch Questi due metodi fungono da verifica a posteriori di dati inseriti. Per quanto riguarda il funzionamento basterà scrivere il codice in esame nel blocco try; il programma svolgerà tutte le istruzioni all’interno di esso, se il codice non genera eccezioni verranno svolte tutte le azioni normalmente. Nel codice dopo il blocco try è posto un blocco catch che al presentarsi di eventuali eccezioni le canalizzerà al suo interno (sarà inoltre necessario scrivere alcune stringhe per dire al programma come comportarsi quando l’eccezione si verifica). Il blocco catch non gestisce in automatico tutte le eccezioni, infatti si deve specificare il tipo di eccezione su cui operare (valore non valido, tipo di carattere non corretto, ecc. ). Un singolo blocco try può essere seguito anche da più di un blocco catch, in modo da riuscire a gestire più eccezioni contemporaneamente. Generare eccezioni In alcuni casi vi è la possibilità di generare eccezioni in previsione di un possibile errore a questo fine esiste un’istruzione chiamata Throw che svolge proprio questo compito. Se ad esempio si crea un sistema che scrive dei numeri da uno a cinque aggiungendo un blocco throw alla fine di esso con le dovute istruzioni al suo interno, una volta che il ciclo sarà finito e tutti e cinque i numeri saranno scritti, genererà l’eccezione e la scriverà in output. Metodi e dati statici In .Net Framework esiste una classe chiamata “Math” che contiene molte funzioni matematiche poste come metodi ad esempio coseno (cos( ) ), seno (sin( ) ), radice quadrata(sqrt( ) ), ecc. . Questi metodi non vengono implementati come dei metodi di istanza (interni alla classe), perciò non necessitano della creazione di un nuovo oggetto math. Essendo statici vengono solamente richiamati e non hanno bisogno di essere definiti nuovamente. 12
1.10 Copia di variabili e classi Variabili: int i = 12; int copia = i; In questo caso si generano due variabili: “i” e “copia” che hanno entrambe il valore 12. Classi: Cerchio C = new Cerchio (12) ; Cerchio D = C; Nelle classi invece quando si genera una copia come nel caso soprastante esiste un solo oggetto Cerchio a cui fanno riferimento sia C che D. 1.11 Parametri ref I parametri ref funzionano all’incirca come delle copie ma con una differenza fondamentale. Infatti un parametro a cui viene aggiunta la parola chiave “ref” come prefisso, non diventa una copia ma un alias. Di conseguenza ogni modifica che viene apportata alla variabile originale esegue una modifica anche sulla variabile ref. out Il funzionamento è molto simile al parametro ref con la differenza che un metodo deve assegnare un valore al parametro out. 13
1.12 Stack ed Heap Stack ed Heap sono entrambe locazioni di memoria ma il loro funzionamento è molto diverso: • STACK : acquisisce richiami di metodi, parametri e variabili che necessitano di uno spazio nella memoria dove “esistere” e successivamente anche dell’assegnazione di un valore. • HEAP: acquisisce creazioni di oggetti, ovvero istanze di una o più classi, tramite la parola chiave new ed una chiamata ad un costruttore. 1.13 Boxing ed Unboxing boxing Con questo temine si definisce l’azione di convertire un’istanza di tipo valore in un oggetto di tipo riferimento. unboxing Operazione inversa di boxing, permette di scartare, o meglio, estrarre un oggetto, che precedentemente aveva subito un processo di boxing. 1.14 Enumerazioni Si supponga di voler creare un programma per le varie stagioni dell’anno. A tale proposito si associno i valori 0, 1, 2, 3 rispettivamente a Primavera, Estate, Autunno, Inverno. Tuttavia questa soluzione non è ottimale perché gli stessi valori 0, 1, 2, 3 potrebbero essere assunti da qualsiasi altra variabile. Per ovviare a questo problema esiste la parola chiave “enum” che limita i valori ad un gruppo specifico di nomi. 1.15 Tipi struttura Una struttura è un tipo di valore personalizzato nel quale va specificata la parola chiave “struct”. A questa struttura possono essere associati metodi, campi e costruttori specifici. 14
1.16 Differenze tra strutture e classi Strutture e classi semanticamente sono molto simili, ma esistono delle differenze molto importanti: • Se una struttura dichiara un costruttore esso deve avere dei parametri. In una classe non deve obbligatoriamente averli • In una struttura il compilatore crea in automatico il costruttore predefinito. In una classe il compilatore crea il costruttore solo se non viene creato in modo esplicito. risposte ad alcune domande : Struttura Classe Il tipo è un tipo valore o un tipo riferimento ? Tipo valore Tipo riferimento Le istanze sono assegnate Denominate valori Denominate oggetti all’Heap o allo Stack ? assegnate allo assegnate all’Heap Stack È possibile dichiarare un costruttore predefinito ? NO SI Se si dichiara una costruttore personalizzato, il costruttore predefinito viene creato lo stesso SI NO dal compilatore ? Se non si inizializza un campo di un costruttore personalizzato, il campo viene inizializzato NO SI automaticamente dal compilatore ? È consentito inizializzare campi di istanza nel punto in cui vengono NO SI dichiarati ? 1.17 Copia delle variabili di struttura Le variabili di struttura possono essere copiate con la funzione “copy” solamente nel caso in cui tutti i campi della struttura siano assegnati in modo preciso. Infatti generare una copia di una variabile di struttura nel modo scorretto comporterà un errore ed il programma non funzionerà. 15
1.18 Equivalenze tra parola chiave e tipo Per la creazione di valori sono generabili due metodi: le enumerazioni e le strutture. Per esempio, la parola chiave int è un alias del tipo struttura chiamato Int32 incluso nello spazio di nomi System. Infatti nelle le stringhe di codice seguenti per il compilatore sono equivalenti: int numero = 42 System.Int32 numero = 42; 1.19 Classe System.Array Tutti i tipi delle matrici (int [ ], double [ ], object [ ], ecc. ) ereditano la classe System.Array quindi le seguenti parti di codice non hanno differenza: int [ ] pins = new int [4] { 9, 3, 2, 5}; Array pins = new int [4] { 9, 3, 2, 5}; La classe tuttavia non può utilizzare la sintassi abbreviata ( int [ ] pins = { 9, 3, 2, 5}; ). Questa classe, per copiare gli elementi di una matrice non usa “for” ma “CopyTo”. 1.20 Definizione di classi collection System.Collections contiene numerose classi; la sua funzione è proprio quella di raggruppare elementi. tutte le classi “Collection” accettano, memorizzano e restituiscono solo elementi in forma di oggetti. La principale differenza tra una matrice di int ed una matrice di interi è che la matrice int contiene delle caselle alle quali sono già assegnati dei valori, mentre nelle matrici di interi non sono assegnati, ma sono richiamati dalla memoria. 1.21 ArrayList “ArrayList” è una classe che serve a spostare degli elementi all’interno di una matrice. Le sue principali funzioni sono: • Remove: rimuove un elemento alla fine di una classe ArrayList (lo spostamento degli elementi viene gestito automaticamente). • Add: aggiunge un elemento alla fine di una classe ArrayList (il ridimensionamento degli elementi viene gestito automaticamente). • Insert: inserisce un elemento in una classe ArrayList (il ridimensionamento degli elementi viene gestito automaticamente). 16
1.22 Queue “Queue” (che significa coda) è una classe che implementa l’insieme FIFO (first in – first out) dove un elemento viene aggiunto alla fine della coda (ENQUEUE) mentre quando viene rimosso abbandona l’insieme dall’inizio della coda (DEQUEUE). Questa classe offre il massimo controllo della posizione in cui gli elementi sono assegnati all’interno della classe. 1.23 Stack “Stack” (che significa pila) è una classe che implementa l’insieme LIFO (last in – first out) dove un elemento viene aggiunto alla cima della pila (PUSH) mentre quando viene rimosso abbandona l’insieme dall’inizio della pila (POP). Questa classe offre il massimo controllo della posizione in cui gli elementi sono assegnati all’interno della classe. 1.24 SortedList “SortedList” è una classe che offre la possibilità di inserire, al posto dei valori di una matrice classica (matrice di int), una matrice di valori di tipo string, double e time. Questa classe esegue una mappatura e riordina le chiavi (ad esempio tutte le string ) in ordine alfabetico. La classe non supporta chiavi duplicate. 1.25 Ereditarietà Nei paragrafi precedenti è già stato spiegato brevemente il concetto di ereditarietà di una classe ma vale la pena riprenderlo per spiegare meglio alcune cose. Nell’immagine ogni cerchio rappresenta una classe; nella classe “mammiferi” vi è la classe gatto nella quale esistono i più diversi tipi di gatto (persiano, certosino, sieìamese, ecc. ). Attraverso l’ereditarietà si dice che ogni gatto è mammifero, indipendentemente da che tipo di gatto sia. 17
1.26 Chiamata dei costruttori di una classe di base Un costruttore della classe derivata deve richiamare il costruttore della classe di base corrispondente attraverso la parola chiave “base” di modo che il sistema vada a recuperare il costruttore dalla classe base per poi utilizzarlo effettivamente nella classe derivata. 1.27 Metodi New Se una classe di base ed una derivata dichiarano due metodi aventi lo stesso nome è preferibile rinominare uno dei due metodi in un modo differente, altrimenti si genererebbero conflitti e fornendo un errore. 1.28 Metodi Virtuali Un metodo virtuale sfrutta il polimorfismo, ossia la possibilità di implementare un metodo più volte. Nella classe base il metodo dovrà essere specificato con la parola chiave “virtual”. 1.29 Metodi Override Il metodo override serve per richiamare un metodo virtuale in una classe derivata. Infatti il metodo virtuale necessita, per essere richiamato, necessita del metodo override che passa al sistema una direttiva per andare a recuperare il metodo virtuale. 1.30 Regole metodi virtual ed override Elenco delle principali regole di utilizzo dei metodi virtual e di quelli override: • Non è consentito dichiarare un metodo privato tramite le parola chiave virtual ed override. • I due metodi devono essere identici (stesso nome, stessi tipi di parametro e stesso tipo restituito). • Ai due metodi deve essere associato lo stesso tipo di accesso. • È possibile eseguire l’override solo dei metodi virtuali • Un metodo override è implicitamente un metodo virtuale ed è quindi possibile eseguire un override di una classe derivata successiva. 18
1.31 Accesso protetto Tramite public e private vengono impostati due tipi di accesso estremi: nel primo caso i membri sono sempre accessibili, mentre nel secondo caso cono accessibili solamente all’interno della classe. Per generare una correlazione tra la classe derivata e la classe base è necessario specificare la parola chiave protected con la quale: • Una classe derivata può accedere ad un membro protetto di una classe di base, ovvero all’interno della classe derivata tale membro è in realtà un membro pubblico;. • Una classe non derivata non può accedere ad un membro di una classe protetto, ovvero all’interno della classe non derivata un membro protetto è in realtà un membro privato. Dove con membro si intente un metodo, una variabile, ecc.. 1.32 Interfacce Un’interfaccia non è un membro. Un interfaccia può contenere diversi membri (metodi, proprietà, ecc. ) dei quali sono definiti solo i nomi e non le loro effettive implementazioni. In un’interfaccia, a differenza dei metodi virtuali e di override, i metodi sono pubblici e possono essere implementati in qualsiasi classe senza dover specificare se questa sia di base oppure derivata. Nell’esempio: quando si implementa un’interfaccia, è necessario assicurarsi che: • Il metodo deve essere dichiarato esplicitamente; • I tipi restituiti devono essere gli stessi; • I nomi dei metodi devono essere gli stessi; • I parametri, se specificati, devono essere uguali, compresi i modificatori di parola chiave ref e out. L’unica eccezione è il modificatore di parola chiave parms. 19
Puoi anche leggere