C # - Guida rapida
C # è un linguaggio di programmazione moderno, generico e orientato agli oggetti sviluppato da Microsoft e approvato dalla European Computer Manufacturers Association (ECMA) e dalla International Standards Organization (ISO).
C # è stato sviluppato da Anders Hejlsberg e dal suo team durante lo sviluppo di .Net Framework.
C # è progettato per Common Language Infrastructure (CLI), che consiste nel codice eseguibile e nell'ambiente di runtime che consente l'uso di vari linguaggi di alto livello su diverse piattaforme e architetture di computer.
I seguenti motivi rendono C # un linguaggio professionale ampiamente utilizzato:
- È un linguaggio di programmazione moderno e generico
- È orientato agli oggetti.
- È orientato ai componenti.
- È facile da imparare.
- È un linguaggio strutturato.
- Produce programmi efficienti.
- Può essere compilato su una varietà di piattaforme di computer.
- È una parte di .Net Framework.
Funzionalità di programmazione avanzate di C #
Sebbene i costrutti C # seguano da vicino i linguaggi tradizionali di alto livello, C e C ++ ed essendo un linguaggio di programmazione orientato agli oggetti. Ha una forte somiglianza con Java, ha numerose caratteristiche di programmazione forti che lo rendono accattivante per un numero di programmatori in tutto il mondo.
Di seguito è riportato l'elenco di alcune importanti funzionalità di C #:
- Condizioni booleane
- Raccolta automatica dei rifiuti
- Libreria standard
- Controllo delle versioni degli assembly
- Proprietà ed eventi
- Delegati e gestione eventi
- Generici facili da usare
- Indexers
- Compilazione condizionale
- Multithreading semplice
- LINQ ed espressioni Lambda
- Integrazione con Windows
Provalo Opzione online
Abbiamo configurato l'ambiente di programmazione C # online, in modo che tu possa compilare ed eseguire tutti gli esempi disponibili online. Ti dà fiducia in ciò che stai leggendo e ti consente di verificare i programmi con diverse opzioni. Sentiti libero di modificare qualsiasi esempio ed eseguirlo online.
Prova il seguente esempio utilizzando il nostro compilatore online disponibile su CodingGround
using System; namespace HelloWorldApplication { class HelloWorld { static void Main(string[] args) { /* my first program in C# */ Console.WriteLine("Hello World"); Console.ReadKey(); } } }
Per la maggior parte degli esempi forniti in questo tutorial, troverai un'opzione Provalo nelle sezioni del codice del nostro sito Web nell'angolo in alto a destra che ti porterà al compilatore online. Quindi usalo e goditi il tuo apprendimento.
In questo capitolo discuteremo gli strumenti necessari per creare la programmazione C #. Abbiamo già detto che C # fa parte del framework .Net e viene utilizzato per scrivere applicazioni .Net. Pertanto, prima di discutere gli strumenti disponibili per l'esecuzione di un programma C #, è necessario comprendere in che modo C # si relaziona al framework .Net.
Il .Net Framework
.Net framework è una piattaforma rivoluzionaria che ti aiuta a scrivere i seguenti tipi di applicazioni:
- Applicazioni Windows
- Applicazioni web
- servizi web
Le applicazioni .Net framework sono applicazioni multipiattaforma. Il framework è stato progettato in modo tale da poter essere utilizzato da uno qualsiasi dei seguenti linguaggi: C #, C ++, Visual Basic, Jscript, COBOL, ecc. Tutti questi linguaggi possono accedere al framework e comunicare tra loro.
Il framework .Net è costituito da un'enorme libreria di codici utilizzati dai linguaggi client come C #. Di seguito sono riportati alcuni dei componenti del framework .Net:
- Common Language Runtime (CLR)
- La libreria di classi .Net Framework
- Specifica del linguaggio comune
- Sistema di tipo comune
- Metadati e assembly
- Windows Form
- ASP.Net e ASP.Net AJAX
- ADO.Net
- Windows Workflow Foundation (WF)
- Windows Presentation Foundation
- Windows Communication Foundation (WCF)
- LINQ
Per i lavori eseguiti da ciascuno di questi componenti, vedere ASP.Net - Introduzione e per i dettagli di ciascun componente, consultare la documentazione di Microsoft.
Ambiente di sviluppo integrato (IDE) per C #
Microsoft fornisce i seguenti strumenti di sviluppo per la programmazione C #:
- Visual Studio 2010 (VS)
- Visual C # 2010 Express (VCE)
- Visual Web Developer
Gli ultimi due sono disponibili gratuitamente dal sito Web ufficiale di Microsoft. Utilizzando questi strumenti, è possibile scrivere tutti i tipi di programmi C # da semplici applicazioni della riga di comando ad applicazioni più complesse. È inoltre possibile scrivere file di codice sorgente C # utilizzando un editor di testo di base, come Blocco note, e compilare il codice in assembly utilizzando il compilatore della riga di comando, che fa di nuovo parte di .NET Framework.
Le versioni Visual C # Express e Visual Web Developer Express sono versioni ridotte di Visual Studio e hanno lo stesso aspetto. Conservano la maggior parte delle funzionalità di Visual Studio. In questo tutorial abbiamo utilizzato Visual C # 2010 Express.
Puoi scaricarlo da Microsoft Visual Studio . Viene installato automaticamente sulla tua macchina.
Nota: è necessaria una connessione Internet attiva per installare l'edizione rapida.
Scrittura di programmi C # su Linux o Mac OS
Sebbene .NET Framework venga eseguito sul sistema operativo Windows, esistono alcune versioni alternative che funzionano su altri sistemi operativi. Monoè una versione open source di .NET Framework che include un compilatore C # e funziona su diversi sistemi operativi, comprese varie versioni di Linux e Mac OS. Si prega di controllare Go Mono .
Lo scopo dichiarato di Mono non è solo quello di essere in grado di eseguire applicazioni Microsoft .NET su più piattaforme, ma anche di fornire strumenti di sviluppo migliori per gli sviluppatori Linux. Mono può essere eseguito su molti sistemi operativi tra cui Android, BSD, iOS, Linux, OS X, Windows, Solaris e UNIX.
Prima di studiare gli elementi costitutivi di base del linguaggio di programmazione C #, esaminiamo una struttura minima del programma C # in modo da poterla prendere come riferimento nei prossimi capitoli.
Creazione del programma Hello World
Il programma AC # è composto dalle seguenti parti:
- Dichiarazione dello spazio dei nomi
- Una classe
- Metodi di classe
- Attributi di classe
- Un metodo principale
- Dichiarazioni ed espressioni
- Comments
Esaminiamo un semplice codice che stampa le parole "Hello World" -
using System;
namespace HelloWorldApplication {
class HelloWorld {
static void Main(string[] args) {
/* my first program in C# */
Console.WriteLine("Hello World");
Console.ReadKey();
}
}
}
Quando questo codice viene compilato ed eseguito, produce il seguente risultato:
Hello World
Esaminiamo le varie parti del programma dato:
La prima riga del programma using System; - il using la parola chiave viene utilizzata per includere il System spazio dei nomi nel programma. Un programma ha generalmente più fileusing dichiarazioni.
La riga successiva ha l'estensione namespacedichiarazione. UNnamespaceè una raccolta di classi. Lo spazio dei nomi HelloWorldApplication contiene la classe HelloWorld .
La riga successiva ha un'estensione classdichiarazione, la classe HelloWorld contiene i dati e le definizioni dei metodi utilizzati dal programma. Le classi generalmente contengono più metodi. I metodi definiscono il comportamento della classe. Tuttavia, la classe HelloWorld ha un solo metodo Main.
La riga successiva definisce il file Main metodo, che è il entry pointper tutti i programmi C #. IlMain metodo afferma cosa fa la classe quando viene eseguita.
La riga successiva /*...*/ viene ignorata dal compilatore e viene aggiunta comments nel programma.
Il metodo Main ne specifica il comportamento con l'istruzione Console.WriteLine("Hello World");
WriteLine è un metodo della classe Console definita nello spazio dei nomi System . Questa istruzione genera il messaggio "Hello, World!" da visualizzare sullo schermo.
L'ultima riga Console.ReadKey();è per gli utenti VS.NET. In questo modo il programma attende la pressione di un tasto e impedisce l'esecuzione e la chiusura rapida dello schermo quando il programma viene avviato da Visual Studio .NET.
Vale la pena notare i seguenti punti:
- C # distingue tra maiuscole e minuscole.
- Tutte le istruzioni e le espressioni devono terminare con un punto e virgola (;).
- L'esecuzione del programma inizia con il metodo Main.
- A differenza di Java, il nome del file del programma potrebbe essere diverso dal nome della classe.
Compilazione ed esecuzione del programma
Se si utilizza Visual Studio.Net per la compilazione e l'esecuzione di programmi C #, eseguire i passaggi seguenti:
Avvia Visual Studio.
Sulla barra dei menu, scegli File -> Nuovo -> Progetto.
Scegli Visual C # dai modelli e quindi scegli Windows.
Scegli l'applicazione console.
Specificare un nome per il progetto e fare clic sul pulsante OK.
Questo crea un nuovo progetto in Esplora soluzioni.
Scrivi codice nell'editor del codice.
Fare clic sul pulsante Esegui o premere il tasto F5 per eseguire il progetto. Viene visualizzata una finestra del prompt dei comandi che contiene la riga Hello World.
È possibile compilare un programma C # utilizzando la riga di comando anziché l'IDE di Visual Studio -
Apri un editor di testo e aggiungi il codice sopra menzionato.
Salva il file come helloworld.cs
Apri lo strumento del prompt dei comandi e vai alla directory in cui hai salvato il file.
genere csc helloworld.cs e premi invio per compilare il tuo codice.
Se non ci sono errori nel codice, il prompt dei comandi ti porta alla riga successiva e genera helloworld.exe file eseguibile.
genere helloworld per eseguire il tuo programma.
Puoi vedere l'output Hello World stampato sullo schermo.
C # è un linguaggio di programmazione orientato agli oggetti. Nella metodologia di programmazione orientata agli oggetti, un programma è costituito da vari oggetti che interagiscono tra loro tramite azioni. Le azioni che un oggetto può intraprendere sono chiamate metodi. Si dice che oggetti dello stesso tipo abbiano lo stesso tipo o che appartengano alla stessa classe.
Ad esempio, consideriamo un oggetto Rectangle. Ha attributi come lunghezza e larghezza. A seconda del progetto, potrebbe essere necessario modi per accettare i valori di questi attributi, calcolare l'area e visualizzare i dettagli.
Esaminiamo l'implementazione di una classe Rectangle e discutiamo la sintassi di base di C #:
using System;
namespace RectangleApplication {
class Rectangle {
// member variables
double length;
double width;
public void Acceptdetails() {
length = 4.5;
width = 3.5;
}
public double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle();
r.Acceptdetails();
r.Display();
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Length: 4.5
Width: 3.5
Area: 15.75
La parola chiave utilizzando
La prima istruzione in qualsiasi programma C # è
using System;
Il usingla parola chiave viene utilizzata per includere gli spazi dei nomi nel programma. Un programma può includere più istruzioni using.
La parola chiave della classe
Il class parola chiave viene utilizzata per dichiarare una classe.
Commenti in C #
I commenti vengono utilizzati per spiegare il codice. I compilatori ignorano le voci di commento. I commenti su più righe nei programmi C # iniziano con / * e terminano con i caratteri * / come mostrato di seguito -
/* This program demonstrates
The basic syntax of C# programming
Language */
I commenti su una sola riga sono indicati dal simbolo "//". Per esempio,
}//end class Rectangle
Variabili membro
Le variabili sono attributi o membri di dati di una classe, utilizzati per memorizzare i dati. Nel programma precedente, la classe Rectangle ha due variabili membro denominate length e width .
Funzioni membro
Le funzioni sono un insieme di istruzioni che eseguono un'attività specifica. Le funzioni membro di una classe vengono dichiarate all'interno della classe. La nostra classe di esempio Rectangle contiene tre funzioni membro: AcceptDetails , GetArea e Display .
Istanziare una classe
Nel programma precedente, la classe ExecuteRectangle contiene il metodo Main () e crea un'istanza della classe Rectangle .
Identificatori
Un identificatore è un nome utilizzato per identificare una classe, una variabile, una funzione o qualsiasi altro elemento definito dall'utente. Le regole di base per la denominazione delle classi in C # sono le seguenti:
Un nome deve iniziare con una lettera che potrebbe essere seguita da una sequenza di lettere, cifre (0 - 9) o trattino basso. Il primo carattere in un identificatore non può essere una cifra.
Non deve contenere spazi o simboli incorporati come? - +! @ #% ^ & * () [] {}. ; : "'/ e \. Tuttavia, è possibile utilizzare un trattino basso (_).
Non dovrebbe essere una parola chiave C #.
Parole chiave C #
Le parole chiave sono parole riservate predefinite per il compilatore C #. Queste parole chiave non possono essere utilizzate come identificatori. Tuttavia, se desideri utilizzare queste parole chiave come identificatori, puoi anteporre alla parola chiave il carattere @.
In C #, alcuni identificatori hanno un significato speciale nel contesto del codice, ad esempio get e set sono chiamati parole chiave contestuali.
La tabella seguente elenca le parole chiave riservate e le parole chiave contestuali in C # -
Parole chiave riservate | ||||||
---|---|---|---|---|---|---|
astratto | come | base | bool | rompere | byte | Astuccio |
catturare | char | controllato | classe | const | Continua | decimale |
predefinito | delegare | fare | Doppio | altro | enum | evento |
esplicito | esterno | falso | finalmente | fisso | galleggiante | per |
per ciascuno | vai a | Se | implicito | in | in (modificatore generico) | int |
interfaccia | interno | è | serratura | lungo | spazio dei nomi | nuovo |
nullo | oggetto | operatore | su | out (modificatore generico) | oltrepassare | params |
privato | protetto | pubblico | sola lettura | rif | ritorno | sbyte |
sigillato | corto | taglia di | stackalloc | statico | corda | struct |
interruttore | Questo | gettare | vero | provare | tipo di | uint |
ulong | deselezionato | pericoloso | ushort | utilizzando | virtuale | vuoto |
volatile | mentre | |||||
Parole chiave contestuali | ||||||
Inserisci | alias | ascendente | discendente | dinamico | a partire dal | ottenere |
globale | gruppo | in | aderire | permettere | ordinato da | parziale (tipo) |
parziale (metodo) |
rimuovere | Selezionare | impostato |
Le variabili in C # sono classificate nei seguenti tipi:
- Tipi di valore
- Tipi di riferimento
- Tipi di puntatore
Tipo di valore
Alle variabili del tipo di valore può essere assegnato direttamente un valore. Sono derivati dalla classe System.ValueType.
I tipi di valore contengono direttamente dati. Alcuni esempi sonoint, char, and float, che memorizza rispettivamente numeri, alfabeti e numeri in virgola mobile. Quando dichiari un fileint type, il sistema alloca memoria per memorizzare il valore.
La tabella seguente elenca i tipi di valore disponibili in C # 2010 -
genere | Rappresenta | Gamma | Valore predefinito |
---|---|---|---|
bool | Valore booleano | Vero o falso | Falso |
byte | Intero senza segno a 8 bit | Da 0 a 255 | 0 |
char | Carattere Unicode a 16 bit | U +0000 a U + ffff | "\ 0" |
decimale | Valori decimali precisi a 128 bit con 28-29 cifre significative | (Da -7,9 x 10 da 28 a 7,9 x 10 28 ) / 10 da 0 a 28 | 0,0M |
Doppio | Tipo a virgola mobile a doppia precisione a 64 bit | (+/-) 5,0 x 10 da -324 a (+/-) 1,7 x 10 308 | 0.0D |
galleggiante | Tipo a virgola mobile a precisione singola a 32 bit | Da -3,4 x 10 38 a + 3,4 x 10 38 | 0.0F |
int | Tipo intero con segno a 32 bit | -2.147.483.648 a 2.147.483.647 | 0 |
lungo | Tipo intero con segno a 64 bit | -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 | 0L |
sbyte | Tipo intero con segno a 8 bit | Da -128 a 127 | 0 |
corto | Tipo intero con segno a 16 bit | Da -32.768 a 32.767 | 0 |
uint | Tipo intero senza segno a 32 bit | Da 0 a 4.294.967.295 | 0 |
ulong | Tipo intero senza segno a 64 bit | Da 0 a 18.446.744.073.709.551.615 | 0 |
ushort | Tipo intero senza segno a 16 bit | Da 0 a 65.535 | 0 |
Per ottenere la dimensione esatta di un tipo o di una variabile su una particolare piattaforma, puoi utilizzare il sizeofmetodo. L'espressione sizeof (tipo) restituisce la dimensione di archiviazione dell'oggetto o del tipo in byte. Di seguito è riportato un esempio per ottenere la dimensione del tipo int su qualsiasi macchina:
using System;
namespace DataTypeApplication {
class Program {
static void Main(string[] args) {
Console.WriteLine("Size of int: {0}", sizeof(int));
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Size of int: 4
Tipo di riferimento
I tipi di riferimento non contengono i dati effettivi memorizzati in una variabile, ma contengono un riferimento alle variabili.
In altre parole, si riferiscono a una posizione di memoria. Utilizzando più variabili, i tipi di riferimento possono fare riferimento a una posizione di memoria. Se i dati nella posizione di memoria vengono modificati da una delle variabili, l'altra variabile riflette automaticamente questo cambiamento di valore. Esempio dibuilt-in i tipi di riferimento sono: object, dynamic, e string.
Tipo di oggetto
Il Object Typeè la classe base definitiva per tutti i tipi di dati in C # Common Type System (CTS). Object è un alias per la classe System.Object. Ai tipi di oggetto possono essere assegnati valori di qualsiasi altro tipo, tipo di valore, tipo di riferimento, tipo predefinito o definito dall'utente. Tuttavia, prima di assegnare valori, è necessaria la conversione del tipo.
Quando un tipo di valore viene convertito in un tipo di oggetto, viene chiamato boxing e d'altra parte, quando un tipo di oggetto viene convertito in un tipo di valore, viene chiamato unboxing.
object obj;
obj = 100; // this is boxing
Tipo dinamico
È possibile memorizzare qualsiasi tipo di valore nella variabile del tipo di dati dinamico. Il controllo del tipo per questi tipi di variabili viene eseguito in fase di esecuzione.
La sintassi per la dichiarazione di un tipo dinamico è -
dynamic <variable_name> = value;
Per esempio,
dynamic d = 20;
I tipi dinamici sono simili ai tipi di oggetto tranne per il fatto che il controllo del tipo per le variabili del tipo di oggetto avviene in fase di compilazione, mentre quello per le variabili di tipo dinamico avviene in fase di esecuzione.
Tipo di stringa
Il String Typeconsente di assegnare qualsiasi valore di stringa a una variabile. Il tipo di stringa è un alias per la classe System.String. È derivato dal tipo di oggetto. Il valore per un tipo di stringa può essere assegnato utilizzando stringhe letterali in due forme: quoted e @quoted.
Per esempio,
String str = "Tutorials Point";
Una stringa letterale @quoted ha il seguente aspetto:
@"Tutorials Point";
I tipi di riferimento definiti dall'utente sono: class, interface o delegate. Discuteremo questi tipi nel capitolo successivo.
Tipo di puntatore
Le variabili del tipo di puntatore memorizzano l'indirizzo di memoria di un altro tipo. I puntatori in C # hanno le stesse funzionalità dei puntatori in C o C ++.
La sintassi per la dichiarazione di un tipo di puntatore è -
type* identifier;
Per esempio,
char* cptr;
int* iptr;
Discuteremo i tipi di puntatore nel capitolo "Codici non sicuri".
La conversione del tipo sta convertendo un tipo di dati in un altro tipo. È anche noto come Type Casting. In C #, il casting dei tipi ha due forme:
Implicit type conversion- Queste conversioni vengono eseguite da C # in modo indipendente dai tipi. Ad esempio, le conversioni da tipi integrali più piccoli a quelli più grandi e le conversioni da classi derivate a classi base.
Explicit type conversion- Queste conversioni vengono eseguite esplicitamente dagli utenti utilizzando le funzioni predefinite. Le conversioni esplicite richiedono un operatore cast.
L'esempio seguente mostra una conversione di tipo esplicita:
using System;
namespace TypeConversionApplication {
class ExplicitConversion {
static void Main(string[] args) {
double d = 5673.74;
int i;
// cast double to int.
i = (int)d;
Console.WriteLine(i);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
5673
Metodi di conversione del tipo C #
C # fornisce i seguenti metodi di conversione del tipo incorporati:
Sr.No. | Metodi e descrizione |
---|---|
1 | ToBoolean Converte un tipo in un valore booleano, ove possibile. |
2 | ToByte Converte un tipo in un byte. |
3 | ToChar Converte un tipo in un singolo carattere Unicode, ove possibile. |
4 | ToDateTime Converte un tipo (intero o tipo stringa) in strutture data-ora. |
5 | ToDecimal Converte un tipo a virgola mobile o intero in un tipo decimale. |
6 | ToDouble Converte un tipo in un doppio tipo. |
7 | ToInt16 Converte un tipo in un numero intero a 16 bit. |
8 | ToInt32 Converte un tipo in un numero intero a 32 bit. |
9 | ToInt64 Converte un tipo in un intero a 64 bit. |
10 | ToSbyte Converte un tipo in un tipo di byte con segno. |
11 | ToSingle Converte un tipo in un piccolo numero in virgola mobile. |
12 | ToString Converte un tipo in una stringa. |
13 | ToType Converte un tipo in un tipo specificato. |
14 | ToUInt16 Converte un tipo in un tipo int senza segno. |
15 | ToUInt32 Converte un tipo in un tipo lungo senza segno. |
16 | ToUInt64 Converte un tipo in un numero intero grande senza segno. |
L'esempio seguente converte vari tipi di valore in tipo stringa:
using System;
namespace TypeConversionApplication {
class StringConversion {
static void Main(string[] args) {
int i = 75;
float f = 53.005f;
double d = 2345.7652;
bool b = true;
Console.WriteLine(i.ToString());
Console.WriteLine(f.ToString());
Console.WriteLine(d.ToString());
Console.WriteLine(b.ToString());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
75
53.005
2345.7652
True
Una variabile non è altro che un nome dato a un'area di memoria che i nostri programmi possono manipolare. Ogni variabile in C # ha un tipo specifico, che determina la dimensione e il layout della memoria della variabile, l'intervallo di valori che possono essere archiviati all'interno di tale memoria e il set di operazioni che possono essere applicate alla variabile.
I tipi di valore di base forniti in C # possono essere classificati come:
genere | Esempio |
---|---|
Tipi integrali | sbyte, byte, short, ushort, int, uint, long, ulong e char |
Tipi in virgola mobile | galleggiante e doppio |
Tipi decimali | decimale |
Tipi booleani | valori veri o falsi, come assegnati |
Tipi nullable | Tipi di dati nullable |
C # consente anche di definire altri tipi di valore di variabili come enum e tipi di riferimento di variabili come class, che tratteremo nei capitoli successivi.
Definizione di variabili
La sintassi per la definizione di variabile in C # è -
<data_type> <variable_list>;
In questo caso, data_type deve essere un tipo di dati C # valido, inclusi char, int, float, double o qualsiasi tipo di dati definito dall'utente e variable_list può essere costituito da uno o più nomi di identificatori separati da virgole.
Alcune definizioni di variabili valide sono mostrate qui -
int i, j, k;
char c, ch;
float f, salary;
double d;
È possibile inizializzare una variabile al momento della definizione come:
int i = 100;
Inizializzazione delle variabili
Le variabili vengono inizializzate (assegnate un valore) con un segno di uguale seguito da un'espressione costante. La forma generale di inizializzazione è:
variable_name = value;
Le variabili possono essere inizializzate nella loro dichiarazione. L'inizializzatore è costituito da un segno di uguale seguito da un'espressione costante come -
<data_type> <variable_name> = value;
Alcuni esempi sono:
int d = 3, f = 5; /* initializing d and f. */
byte z = 22; /* initializes z. */
double pi = 3.14159; /* declares an approximation of pi. */
char x = 'x'; /* the variable x has the value 'x'. */
È una buona pratica di programmazione inizializzare correttamente le variabili, altrimenti a volte il programma potrebbe produrre risultati imprevisti.
L'esempio seguente utilizza vari tipi di variabili:
using System;
namespace VariableDefinition {
class Program {
static void Main(string[] args) {
short a;
int b ;
double c;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
Console.WriteLine("a = {0}, b = {1}, c = {2}", a, b, c);
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
a = 10, b = 20, c = 30
Accettazione di valori da parte dell'utente
Il Console classe in System lo spazio dei nomi fornisce una funzione ReadLine() per accettare input dall'utente e memorizzarli in una variabile.
Per esempio,
int num;
num = Convert.ToInt32(Console.ReadLine());
La funzione Convert.ToInt32() converte i dati inseriti dall'utente nel tipo di dati int, perché Console.ReadLine() accetta i dati in formato stringa.
Espressioni Lvalue e Rvalue in C #
Esistono due tipi di espressioni in C #:
lvalue - Un'espressione che è un lvalue può apparire come il lato sinistro o destro di un compito.
rvalue - Un'espressione che rappresenta un valore può apparire a destra ma non a sinistra di un compito.
Le variabili sono i valori e quindi possono apparire sul lato sinistro di un compito. I letterali numerici sono rvalues e quindi potrebbero non essere assegnati e non possono essere visualizzati sul lato sinistro. Di seguito è riportata un'istruzione C # valida:
int g = 20;
Ma la seguente non è un'affermazione valida e genererebbe un errore in fase di compilazione -
10 = 20;
Le costanti si riferiscono a valori fissi che il programma non può alterare durante la sua esecuzione. Questi valori fissi sono anche chiamati letterali. Le costanti possono essere di uno qualsiasi dei tipi di dati di base come una costante intera, una costante mobile, una costante di carattere o una stringa letterale. Ci sono anche costanti di enumerazione.
Le costanti vengono trattate come variabili regolari tranne per il fatto che i loro valori non possono essere modificati dopo la loro definizione.
Letterali interi
Un valore letterale intero può essere una costante decimale o esadecimale. Un prefisso specifica la base o la radice: 0x o 0X per esadecimale e non esiste un ID prefisso per decimale.
Un valore letterale intero può anche avere un suffisso che è una combinazione di U e L, rispettivamente per unsigned e long. Il suffisso può essere maiuscolo o minuscolo e può essere in qualsiasi ordine.
Ecco alcuni esempi di valori letterali interi:
212 /* Legal */
215u /* Legal */
0xFeeL /* Legal */
Di seguito sono riportati altri esempi di vari tipi di valori letterali interi:
85 /* decimal */
0x4b /* hexadecimal */
30 /* int */
30u /* unsigned int */
30l /* long */
30ul /* unsigned long */
Valori letterali a virgola mobile
Un valore letterale a virgola mobile ha una parte intera, una virgola decimale, una parte frazionaria e una parte esponente. È possibile rappresentare valori letterali a virgola mobile in forma decimale o esponenziale.
Ecco alcuni esempi di valori letterali in virgola mobile:
3.14159 /* Legal */
314159E-5F /* Legal */
510E /* Illegal: incomplete exponent */
210f /* Illegal: no decimal or exponent */
.e55 /* Illegal: missing integer or fraction */
Mentre si rappresenta in forma decimale, è necessario includere il punto decimale, l'esponente o entrambi; e mentre si rappresenta utilizzando la forma esponenziale è necessario includere la parte intera, la parte frazionaria o entrambe. L'esponente con segno è introdotto da e o E.
Costanti di carattere
I caratteri letterali sono racchiusi tra virgolette singole. Ad esempio, "x" e può essere memorizzato in una semplice variabile di tipo char. Un carattere letterale può essere un carattere semplice (come "x"), una sequenza di escape (come "\ t") o un carattere universale (come "\ u02C0").
Ci sono alcuni caratteri in C # quando sono preceduti da una barra rovesciata. Hanno un significato speciale e sono usati per rappresentare come una nuova riga (\ n) o una tabulazione (\ t). Ecco un elenco di alcuni di questi codici di sequenza di escape:
Sequenza di escape | Senso |
---|---|
\\ | \ personaggio |
\ ' | ' personaggio |
\ " | " personaggio |
\? | ? personaggio |
\un | Allerta o campanello |
\ b | Backspace |
\ f | Avanzamento modulo |
\ n | Nuova linea |
\ r | Ritorno in carrozza |
\ t | Tab orizzontale |
\ v | Scheda verticale |
\ xhh. . . | Numero esadecimale di una o più cifre |
Di seguito è riportato l'esempio per mostrare alcuni caratteri della sequenza di escape:
using System;
namespace EscapeChar {
class Program {
static void Main(string[] args) {
Console.WriteLine("Hello\tWorld\n\n");
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Hello World
Valori letterali stringa
I valori letterali o le costanti stringa sono racchiusi tra virgolette doppie "" o con @ "". Una stringa contiene caratteri simili ai caratteri letterali: caratteri normali, sequenze di escape e caratteri universali.
È possibile suddividere una lunga riga in più righe utilizzando stringhe letterali e separando le parti utilizzando spazi bianchi.
Di seguito sono riportati alcuni esempi di stringhe letterali. Tutte e tre le forme sono stringhe identiche.
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
@"hello dear"
Definizione di costanti
Le costanti vengono definite utilizzando constparola chiave. La sintassi per definire una costante è:
const <data_type> <constant_name> = value;
Il seguente programma dimostra la definizione e l'utilizzo di una costante nel programma:
using System;
namespace DeclaringConstants {
class Program {
static void Main(string[] args) {
const double pi = 3.14159;
// constant declaration
double r;
Console.WriteLine("Enter Radius: ");
r = Convert.ToDouble(Console.ReadLine());
double areaCircle = pi * r * r;
Console.WriteLine("Radius: {0}, Area: {1}", r, areaCircle);
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Enter Radius:
3
Radius: 3, Area: 28.27431
Un operatore è un simbolo che dice al compilatore di eseguire specifiche manipolazioni matematiche o logiche. C # ha un ricco set di operatori incorporati e fornisce il seguente tipo di operatori:
- Operatori aritmetici
- Operatori relazionali
- Operatori logici
- Operatori bit per bit
- Operatori di assegnazione
- Operatori vari
Questo tutorial spiega gli operatori aritmetici, relazionali, logici, bit per bit, di assegnazione e altri uno per uno.
Operatori aritmetici
La tabella seguente mostra tutti gli operatori aritmetici supportati da C #. Assumi variabileA detiene 10 e variabile B tiene 20 quindi -
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
+ | Aggiunge due operandi | A + B = 30 |
- | Sottrae il secondo operando dal primo | A - B = -10 |
* | Moltiplica entrambi gli operandi | A * B = 200 |
/ | Divide il numeratore per il de-numeratore | B / A = 2 |
% | Operatore modulo e resto di dopo una divisione intera | B% A = 0 |
++ | L'operatore di incremento aumenta il valore intero di uno | A ++ = 11 |
- | L'operatore di decremento riduce il valore intero di uno | A-- = 9 |
Operatori relazionali
La tabella seguente mostra tutti gli operatori relazionali supportati da C #. Assumi variabileA detiene 10 e variabile B detiene 20, quindi -
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
== | Controlla se i valori di due operandi sono uguali o meno, in caso affermativo la condizione diventa vera. | (A == B) non è vero. |
! = | Controlla se i valori di due operandi sono uguali o meno, se i valori non sono uguali la condizione diventa vera. | (A! = B) è vero. |
> | Controlla se il valore dell'operando sinistro è maggiore del valore dell'operando destro, in caso affermativo la condizione diventa vera. | (A> B) non è vero. |
< | Controlla se il valore dell'operando sinistro è inferiore al valore dell'operando destro, in caso affermativo la condizione diventa vera. | (A <B) è vero. |
> = | Controlla se il valore dell'operando sinistro è maggiore o uguale al valore dell'operando destro, in caso affermativo la condizione diventa vera. | (A> = B) non è vero. |
<= | Controlla se il valore dell'operando sinistro è minore o uguale al valore dell'operando destro, in caso affermativo la condizione diventa vera. | (A <= B) è vero. |
Operatori logici
La tabella seguente mostra tutti gli operatori logici supportati da C #. Assumi variabileA contiene il valore booleano vero e variabile B mantiene il valore booleano falso, quindi -
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
&& | Chiamato operatore AND logico. Se entrambi gli operandi sono diversi da zero, la condizione diventa vera. | (A && B) è falso. |
|| | Chiamato Operatore OR logico. Se uno dei due operandi è diverso da zero, la condizione diventa vera. | (A || B) è vero. |
! | Chiamato operatore NOT logico. Utilizzare per invertire lo stato logico del suo operando. Se una condizione è vera, l'operatore NOT logico la renderà falsa. | ! (A && B) è vero. |
Operatori bit per bit
L'operatore bit per bit lavora sui bit ed esegue l'operazione bit per bit. Le tabelle di verità per &, | e ^ sono le seguenti:
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
Assumiamo se A = 60; e B = 13; quindi nel formato binario sono i seguenti:
A = 0011 1100
B = 0000 1101
-------------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~ A = 1100 0011
Gli operatori bit per bit supportati da C # sono elencati nella tabella seguente. Supponiamo che la variabile A contenga 60 e la variabile B ne contenga 13, quindi -
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
& | L'operatore AND binario copia un po 'nel risultato se esiste in entrambi gli operandi. | (A e B) = 12, che è 0000 1100 |
| | L'operatore OR binario copia un bit se esiste in uno degli operandi. | (A | B) = 61, ovvero 0011 1101 |
^ | L'operatore XOR binario copia il bit se è impostato in un operando ma non in entrambi. | (A ^ B) = 49, che è 0011 0001 |
~ | Binary Ones Complement Operator è unario e ha l'effetto di "ribaltare" i bit. | (~ A) = -61, che è 1100 0011 in complemento a 2 a causa di un numero binario con segno. |
<< | Operatore binario di spostamento sinistro. Il valore degli operandi di sinistra viene spostato a sinistra del numero di bit specificato dall'operando di destra. | A << 2 = 240, che è 1111 0000 |
>> | Operatore binario di spostamento a destra. Il valore dell'operando di sinistra viene spostato a destra del numero di bit specificato dall'operando di destra. | A >> 2 = 15, che è 0000 1111 |
Operatori di assegnazione
Sono disponibili i seguenti operatori di assegnazione supportati da C #:
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
= | Operatore di assegnazione semplice, Assegna i valori dagli operandi del lato destro all'operando del lato sinistro | C = A + B assegna il valore di A + B a C |
+ = | Aggiungi operatore di assegnazione AND, aggiunge l'operando destro all'operando sinistro e assegna il risultato all'operando sinistro | C + = A è equivalente a C = C + A |
- = | Sottrai AND operatore di assegnazione, sottrae l'operando destro dall'operando sinistro e assegna il risultato all'operando sinistro | C - = A è equivalente a C = C - A |
* = | Moltiplica AND operatore di assegnazione, moltiplica l'operando destro con l'operando sinistro e assegna il risultato all'operando sinistro | C * = A è equivalente a C = C * A |
/ = | Divide AND operatore di assegnazione, divide l'operando sinistro con l'operando destro e assegna il risultato all'operando sinistro | C / = A è equivalente a C = C / A |
% = | Modulo AND operatore di assegnazione, richiede il modulo utilizzando due operandi e assegna il risultato all'operando sinistro | C% = A è equivalente a C = C% A |
<< = | Shift sinistro AND operatore di assegnazione | C << = 2 è uguale a C = C << 2 |
>> = | Spostamento a destra e operatore di assegnazione | C >> = 2 è uguale a C = C >> 2 |
& = | Operatore di assegnazione AND bit per bit | C & = 2 è uguale a C = C & 2 |
^ = | OR bit per bit esclusivo e operatore di assegnazione | C ^ = 2 è uguale a C = C ^ 2 |
| = | OR bit per bit inclusivo e operatore di assegnazione | C | = 2 è uguale a C = C | 2 |
Operatori vari
Ci sono pochi altri operatori importanti tra cui sizeof, typeof e ? : supportato da C #.
Mostra esempi
Operatore | Descrizione | Esempio |
---|---|---|
taglia di() | Restituisce la dimensione di un tipo di dati. | sizeof (int), restituisce 4. |
tipo di() | Restituisce il tipo di una classe. | typeof (StreamReader); |
& | Restituisce l'indirizzo di una variabile. | &un; restituisce l'indirizzo effettivo della variabile. |
* | Puntatore a una variabile. | *un; crea un puntatore denominato "a" a una variabile. |
? : | Espressione condizionale | Se la condizione è vera? Quindi valore X: altrimenti valore Y |
è | Determina se un oggetto è di un certo tipo. | If (Ford is Car) // controlla se Ford è un oggetto della classe Car. |
come | Cast senza sollevare un'eccezione se il cast fallisce. | Object obj = new StringReader ("Hello"); StringReader r = obj as StringReader; |
Precedenza degli operatori in C #
La precedenza degli operatori determina il raggruppamento dei termini in un'espressione. Ciò influisce sulla valutazione di un'espressione. Alcuni operatori hanno la precedenza maggiore di altri; ad esempio, l'operatore di moltiplicazione ha una precedenza maggiore dell'operatore di addizione.
Ad esempio x = 7 + 3 * 2; qui, x è assegnato 13, non 20 perché l'operatore * ha una precedenza maggiore di +, quindi la prima valutazione ha luogo per 3 * 2 e quindi viene aggiunto 7.
Qui, gli operatori con la precedenza più alta vengono visualizzati nella parte superiore della tabella, quelli con la priorità più bassa in fondo. All'interno di un'espressione, gli operatori con precedenza più alta vengono valutati per primi.
Mostra esempi
Categoria | Operatore | Associatività |
---|---|---|
Postfix | () [] ->. ++ - - | Da sinistra a destra |
Unario | + -! ~ ++ - - (tipo) * & sizeof | Da destra a sinistra |
Moltiplicativo | * /% | Da sinistra a destra |
Additivo | + - | Da sinistra a destra |
Cambio | << >> | Da sinistra a destra |
Relazionale | < <= > >= | Left to right |
Equality | == != | Left to right |
Bitwise AND | & | Left to right |
Bitwise XOR | ^ | Left to right |
Bitwise OR | | | Left to right |
Logical AND | && | Left to right |
Logical OR | || | Left to right |
Conditional | ?: | Right to left |
Assignment | = += -= *= /= %=>>= <<= &= ^= |= | Right to left |
Comma | , | Left to right |
Decision making structures requires the programmer to specify one or more conditions to be evaluated or tested by the program, along with a statement or statements to be executed if the condition is determined to be true, and optionally, other statements to be executed if the condition is determined to be false.
Following is the general form of a typical decision making structure found in most of the programming languages −
C# provides following types of decision making statements. Click the following links to check their detail.
Sr.No. | Statement & Description |
---|---|
1 | if statement An if statement consists of a boolean expression followed by one or more statements. |
2 | if...else statement An if statement can be followed by an optional else statement, which executes when the boolean expression is false. |
3 | nested if statements You can use one if or else if statement inside another if or else if statement(s). |
4 | switch statement A switch statement allows a variable to be tested for equality against a list of values. |
5 | nested switch statements You can use one switch statement inside another switch statement(s). |
The ? : Operator
We have covered conditional operator ? : in previous chapter which can be used to replace if...else statements. It has the following general form −
Exp1 ? Exp2 : Exp3;
Where Exp1, Exp2, and Exp3 are expressions. Notice the use and placement of the colon.
The value of a ? expression is determined as follows: Exp1 is evaluated. If it is true, then Exp2 is evaluated and becomes the value of the entire ? expression. If Exp1 is false, then Exp3 is evaluated and its value becomes the value of the expression.
There may be a situation, when you need to execute a block of code several number of times. In general, the statements are executed sequentially: The first statement in a function is executed first, followed by the second, and so on.
Programming languages provide various control structures that allow for more complicated execution paths.
A loop statement allows us to execute a statement or a group of statements multiple times and following is the general from of a loop statement in most of the programming languages −
C# provides following types of loop to handle looping requirements. Click the following links to check their detail.
Sr.No. | Loop Type & Description |
---|---|
1 | while loop It repeats a statement or a group of statements while a given condition is true. It tests the condition before executing the loop body. |
2 | for loop It executes a sequence of statements multiple times and abbreviates the code that manages the loop variable. |
3 | do...while loop It is similar to a while statement, except that it tests the condition at the end of the loop body |
4 | nested loops You can use one or more loop inside any another while, for or do..while loop. |
Loop Control Statements
Loop control statements change execution from its normal sequence. When execution leaves a scope, all automatic objects that were created in that scope are destroyed.
C# provides the following control statements. Click the following links to check their details.
Sr.No. | Control Statement & Description |
---|---|
1 | break statement Terminates the loop or switch statement and transfers execution to the statement immediately following the loop or switch. |
2 | continue statement Causes the loop to skip the remainder of its body and immediately retest its condition prior to reiterating. |
Infinite Loop
A loop becomes infinite loop if a condition never becomes false. The for loop is traditionally used for this purpose. Since none of the three expressions that form the for loop are required, you can make an endless loop by leaving the conditional expression empty.
Example
using System;
namespace Loops {
class Program {
static void Main(string[] args) {
for (; ; ) {
Console.WriteLine("Hey! I am Trapped");
}
}
}
}
When the conditional expression is absent, it is assumed to be true. You may have an initialization and increment expression, but programmers more commonly use the for(;;) construct to signify an infinite loop.
Encapsulationè definito "come il processo di racchiudere uno o più articoli all'interno di un pacchetto fisico o logico". L'incapsulamento, nella metodologia di programmazione orientata agli oggetti, impedisce l'accesso ai dettagli di implementazione.
L'astrazione e l'incapsulamento sono funzionalità correlate nella programmazione orientata agli oggetti. L'astrazione consente di rendere visibili le informazioni rilevanti e l'incapsulamento consente a un programmatore di implementare il livello di astrazione desiderato .
L'incapsulamento viene implementato utilizzando access specifiers. Unaccess specifierdefinisce l'ambito e la visibilità di un membro della classe. C # supporta i seguenti specificatori di accesso:
- Public
- Private
- Protected
- Internal
- Interno protetto
Identificatore di accesso pubblico
Lo specificatore di accesso pubblico consente a una classe di esporre le sue variabili membro e le funzioni membro ad altre funzioni e oggetti. È possibile accedere a qualsiasi membro pubblico dall'esterno della classe.
Il seguente esempio lo illustra:
using System;
namespace RectangleApplication {
class Rectangle {
//member variables
public double length;
public double width;
public double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle();
r.length = 4.5;
r.width = 3.5;
r.Display();
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Length: 4.5
Width: 3.5
Area: 15.75
Nell'esempio precedente, vengono dichiarate le variabili membro length e width public, quindi è possibile accedervi dalla funzione Main () utilizzando un'istanza della classe Rectangle, denominata r.
Anche la funzione membro Display () e GetArea () possono accedere direttamente a queste variabili senza utilizzare alcuna istanza della classe.
Vengono dichiarate anche le funzioni membro Display ()public, quindi è possibile accedervi anche da Main () utilizzando un'istanza della classe Rectangle, denominatar.
Identificatore di accesso privato
Lo specificatore di accesso privato consente a una classe di nascondere le sue variabili membro e le funzioni membro da altre funzioni e oggetti. Solo le funzioni della stessa classe possono accedere ai suoi membri privati. Anche un'istanza di una classe non può accedere ai suoi membri privati.
Il seguente esempio lo illustra:
using System;
namespace RectangleApplication {
class Rectangle {
//member variables
private double length;
private double width;
public void Acceptdetails() {
Console.WriteLine("Enter Length: ");
length = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter Width: ");
width = Convert.ToDouble(Console.ReadLine());
}
public double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle();
r.Acceptdetails();
r.Display();
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Enter Length:
4.4
Enter Width:
3.3
Length: 4.4
Width: 3.3
Area: 14.52
Nell'esempio precedente, vengono dichiarate le variabili membro length e width private, quindi non è possibile accedervi dalla funzione Main (). Le funzioni membro AcceptDetails () e Display () possono accedere a queste variabili. Poiché vengono dichiarate le funzioni membro AcceptDetails () e Display ()public, è possibile accedervi da Main () utilizzando un'istanza della classe Rectangle, denominatar.
Identificatore di accesso protetto
Lo specificatore di accesso protetto consente a una classe figlia di accedere alle variabili membro e alle funzioni membro della sua classe base. In questo modo aiuta a implementare l'ereditarietà. Ne discuteremo più in dettaglio nel capitolo sull'eredità.
Identificatore di accesso interno
Lo specificatore di accesso interno consente a una classe di esporre le proprie variabili membro e funzioni membro ad altre funzioni e oggetti nell'assembly corrente. In altre parole, è possibile accedere a qualsiasi membro con specificatore di accesso interno da qualsiasi classe o metodo definito all'interno dell'applicazione in cui è definito il membro.
Il seguente programma lo illustra:
using System;
namespace RectangleApplication {
class Rectangle {
//member variables
internal double length;
internal double width;
double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle();
r.length = 4.5;
r.width = 3.5;
r.Display();
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Length: 4.5
Width: 3.5
Area: 15.75
Nell'esempio precedente, notare che la funzione membro GetArea () non è dichiarata con alcun identificatore di accesso. Allora quale sarebbe l'identificatore di accesso predefinito di un membro della classe se non ne menzionassimo nessuno? Èprivate.
Identificatore di accesso interno protetto
Lo specificatore di accesso interno protetto consente a una classe di nascondere le proprie variabili membro e funzioni membro da altri oggetti e funzioni di classe, ad eccezione di una classe figlia all'interno della stessa applicazione. Viene utilizzato anche durante l'implementazione dell'ereditarietà.
Un metodo è un gruppo di istruzioni che insieme svolgono un'attività. Ogni programma C # ha almeno una classe con un metodo denominato Main.
Per utilizzare un metodo, è necessario:
- Definisci il metodo
- Chiama il metodo
Definizione di metodi in C #
Quando definisci un metodo, in pratica dichiari gli elementi della sua struttura. La sintassi per la definizione di un metodo in C # è la seguente:
<Access Specifier> <Return Type> <Method Name>(Parameter List) {
Method Body
}
Di seguito sono riportati i vari elementi di un metodo:
Access Specifier - Questo determina la visibilità di una variabile o di un metodo di un'altra classe.
Return type- Un metodo può restituire un valore. Il tipo restituito è il tipo di dati del valore restituito dal metodo. Se il metodo non restituisce alcun valore, il tipo restituito èvoid.
Method name- Il nome del metodo è un identificatore univoco e distingue tra maiuscole e minuscole. Non può essere uguale a qualsiasi altro identificatore dichiarato nella classe.
Parameter list- Racchiusi tra parentesi, i parametri vengono utilizzati per trasmettere e ricevere dati da un metodo. L'elenco dei parametri si riferisce al tipo, all'ordine e al numero dei parametri di un metodo. I parametri sono opzionali; ovvero, un metodo non può contenere parametri.
Method body - Contiene il set di istruzioni necessarie per completare l'attività richiesta.
Esempio
Il seguente frammento di codice mostra una funzione FindMax che accetta due valori interi e restituisce il maggiore dei due. Ha uno specificatore di accesso pubblico, quindi è possibile accedervi dall'esterno della classe utilizzando un'istanza della classe.
class NumberManipulator {
public int FindMax(int num1, int num2) {
/* local variable declaration */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
...
}
Chiamata di metodi in C #
È possibile chiamare un metodo utilizzando il nome del metodo. Il seguente esempio lo illustra:
using System;
namespace CalculatorApplication {
class NumberManipulator {
public int FindMax(int num1, int num2) {
/* local variable declaration */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
static void Main(string[] args) {
/* local variable definition */
int a = 100;
int b = 200;
int ret;
NumberManipulator n = new NumberManipulator();
//calling the FindMax method
ret = n.FindMax(a, b);
Console.WriteLine("Max value is : {0}", ret );
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Max value is : 200
È inoltre possibile chiamare il metodo pubblico da altre classi utilizzando l'istanza della classe. Ad esempio, il metodo FindMax appartiene alla classe NumberManipulator , puoi chiamarlo da un'altra classe Test .
using System;
namespace CalculatorApplication {
class NumberManipulator {
public int FindMax(int num1, int num2) {
/* local variable declaration */
int result;
if(num1 > num2)
result = num1;
else
result = num2;
return result;
}
}
class Test {
static void Main(string[] args) {
/* local variable definition */
int a = 100;
int b = 200;
int ret;
NumberManipulator n = new NumberManipulator();
//calling the FindMax method
ret = n.FindMax(a, b);
Console.WriteLine("Max value is : {0}", ret );
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Max value is : 200
Chiamata al metodo ricorsiva
Un metodo può chiamare se stesso. Questo è noto comerecursion. Di seguito è riportato un esempio che calcola il fattoriale per un dato numero utilizzando una funzione ricorsiva:
using System;
namespace CalculatorApplication {
class NumberManipulator {
public int factorial(int num) {
/* local variable declaration */
int result;
if (num == 1) {
return 1;
}
else {
result = factorial(num - 1) * num;
return result;
}
}
static void Main(string[] args) {
NumberManipulator n = new NumberManipulator();
//calling the factorial method {0}", n.factorial(6));
Console.WriteLine("Factorial of 7 is : {0}", n.factorial(7));
Console.WriteLine("Factorial of 8 is : {0}", n.factorial(8));
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Factorial of 6 is: 720
Factorial of 7 is: 5040
Factorial of 8 is: 40320
Passaggio di parametri a un metodo
Quando viene chiamato il metodo con parametri, è necessario passare i parametri al metodo. Ci sono tre modi in cui i parametri possono essere passati a un metodo:
Sr.No. | Meccanismo e descrizione |
---|---|
1 | Parametri di valore Questo metodo copia il valore effettivo di un argomento nel parametro formale della funzione. In questo caso, le modifiche apportate al parametro all'interno della funzione non hanno effetto sull'argomento. |
2 | Parametri di riferimento Questo metodo copia il riferimento alla posizione di memoria di un argomento nel parametro formale. Ciò significa che le modifiche apportate al parametro influiscono sull'argomento. |
3 | Parametri di output Questo metodo aiuta a restituire più di un valore. |
C # fornisce tipi di dati speciali, il nullable tipi, a cui è possibile assegnare un intervallo di valori normale e valori nulli.
Ad esempio, è possibile memorizzare qualsiasi valore compreso tra -2,147,483,648 e 2,147,483,647 o null in una variabile Nullable <Int32>. Allo stesso modo, puoi assegnare true, false o null in una variabile <bool> Nullable. Sintassi per la dichiarazione di un filenullable il tipo è il seguente -
< data_type> ? <variable_name> = null;
L'esempio seguente dimostra l'uso di tipi di dati nullable:
using System;
namespace CalculatorApplication {
class NullablesAtShow {
static void Main(string[] args) {
int? num1 = null;
int? num2 = 45;
double? num3 = new double?();
double? num4 = 3.14157;
bool? boolval = new bool?();
// display the values
Console.WriteLine("Nullables at Show: {0}, {1}, {2}, {3}", num1, num2, num3, num4);
Console.WriteLine("A Nullable boolean value: {0}", boolval);
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Nullables at Show: , 45, , 3.14157
A Nullable boolean value:
The Null Coalescing Operator (??)
L'operatore di coalescenza null viene utilizzato con i tipi di valore nullable e i tipi di riferimento. Viene utilizzato per convertire un operando nel tipo di un altro operando di tipo valore nullable (o meno), in cui è possibile una conversione implicita.
Se il valore del primo operando è nullo, l'operatore restituisce il valore del secondo operando, altrimenti restituisce il valore del primo operando. Il seguente esempio spiega questo:
using System;
namespace CalculatorApplication {
class NullablesAtShow {
static void Main(string[] args) {
double? num1 = null;
double? num2 = 3.14157;
double num3;
num3 = num1 ?? 5.34;
Console.WriteLine(" Value of num3: {0}", num3);
num3 = num2 ?? 5.34;
Console.WriteLine(" Value of num3: {0}", num3);
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Value of num3: 5.34
Value of num3: 3.14157
Un array memorizza una raccolta sequenziale di dimensioni fisse di elementi dello stesso tipo. Un array viene utilizzato per archiviare una raccolta di dati, ma è spesso più utile pensare a un array come una raccolta di variabili dello stesso tipo archiviate in posizioni di memoria contigue.
Invece di dichiarare variabili individuali, come numero0, numero1, ... e numero99, dichiari una variabile di matrice come numeri e utilizzi numeri [0], numeri [1] e ..., numeri [99] per rappresentare variabili individuali. Un elemento specifico in un array è accessibile da un indice.
Tutti gli array sono costituiti da posizioni di memoria contigue. L'indirizzo più basso corrisponde al primo elemento e l'indirizzo più alto all'ultimo elemento.
Dichiarazione di array
Per dichiarare un array in C #, puoi usare la seguente sintassi:
datatype[] arrayName;
dove,
datatype viene utilizzato per specificare il tipo di elementi nell'array.
[] specifica il rango dell'array. Il rango specifica la dimensione dell'array.
arrayName specifica il nome dell'array.
Per esempio,
double[] balance;
Inizializzazione di un array
La dichiarazione di un array non inizializza l'array nella memoria. Quando la variabile array viene inizializzata, è possibile assegnare valori all'array.
Array è un tipo di riferimento, quindi è necessario utilizzare l'estensione newparola chiave per creare un'istanza dell'array. Per esempio,
double[] balance = new double[10];
Assegnazione di valori a un array
È possibile assegnare valori a singoli elementi dell'array, utilizzando il numero di indice, come -
double[] balance = new double[10];
balance[0] = 4500.0;
È possibile assegnare valori all'array al momento della dichiarazione, come mostrato -
double[] balance = { 2340.0, 4523.69, 3421.0};
Puoi anche creare e inizializzare un array, come mostrato -
int [] marks = new int[5] { 99, 98, 92, 97, 95};
Puoi anche omettere la dimensione dell'array, come mostrato -
int [] marks = new int[] { 99, 98, 92, 97, 95};
È possibile copiare una variabile di matrice in un'altra variabile di matrice di destinazione. In tal caso, sia la destinazione che la sorgente puntano alla stessa posizione di memoria -
int [] marks = new int[] { 99, 98, 92, 97, 95};
int[] score = marks;
Quando si crea una matrice, il compilatore C # inizializza in modo implicito ogni elemento della matrice su un valore predefinito a seconda del tipo di matrice. Ad esempio, per un array int tutti gli elementi vengono inizializzati su 0.
Accesso agli elementi dell'array
Si accede a un elemento indicizzando il nome dell'array. Questo viene fatto inserendo l'indice dell'elemento tra parentesi quadre dopo il nome dell'array. Per esempio,
double salary = balance[9];
Il seguente esempio, dimostra i concetti sopra menzionati dichiarazione, assegnazione e accesso agli array -
using System;
namespace ArrayApplication {
class MyArray {
static void Main(string[] args) {
int [] n = new int[10]; /* n is an array of 10 integers */
int i,j;
/* initialize elements of array n */
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100;
}
/* output each array element's value */
for (j = 0; j < 10; j++ ) {
Console.WriteLine("Element[{0}] = {1}", j, n[j]);
}
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
Utilizzando il ciclo foreach
Nell'esempio precedente, abbiamo utilizzato un ciclo for per accedere a ciascun elemento dell'array. Puoi anche usare un fileforeach istruzione per iterare attraverso un array.
using System;
namespace ArrayApplication {
class MyArray {
static void Main(string[] args) {
int [] n = new int[10]; /* n is an array of 10 integers */
/* initialize elements of array n */
for ( int i = 0; i < 10; i++ ) {
n[i] = i + 100;
}
/* output each array element's value */
foreach (int j in n ) {
int i = j-100;
Console.WriteLine("Element[{0}] = {1}", i, j);
}
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
Matrici C #
Sono presenti alcuni importanti concetti relativi all'array che dovrebbero essere chiari a un programmatore C #:
Sr.No. | Concetto e descrizione |
---|---|
1 | Array multidimensionali C # supporta array multidimensionali. La forma più semplice dell'array multidimensionale è l'array bidimensionale. |
2 | Array frastagliati C # supporta matrici multidimensionali, che sono matrici di matrici. |
3 | Passaggio di array a funzioni È possibile passare alla funzione un puntatore a un array specificando il nome dell'array senza un indice. |
4 | Matrici di parametri Viene utilizzato per passare un numero sconosciuto di parametri a una funzione. |
5 | La classe Array Definita nello spazio dei nomi di sistema, è la classe base per tutti gli array e fornisce varie proprietà e metodi per lavorare con gli array. |
In C # è possibile utilizzare stringhe come array di caratteri, tuttavia, la pratica più comune consiste nell'usare l'estensione stringparola chiave per dichiarare una variabile stringa. La parola chiave string è un alias perSystem.String classe.
Creazione di un oggetto stringa
È possibile creare un oggetto stringa utilizzando uno dei seguenti metodi:
Assegnando una stringa letterale a una variabile String
Utilizzando un costruttore di classi String
Utilizzando l'operatore di concatenazione di stringhe (+)
Recuperando una proprietà o chiamando un metodo che restituisce una stringa
Chiamando un metodo di formattazione per convertire un valore o un oggetto nella relativa rappresentazione di stringa
Il seguente esempio lo dimostra:
using System;
namespace StringApplication {
class Program {
static void Main(string[] args) {
//from string literal and string concatenation
string fname, lname;
fname = "Rowan";
lname = "Atkinson";
char []letters= { 'H', 'e', 'l', 'l','o' };
string [] sarray={ "Hello", "From", "Tutorials", "Point" };
string fullname = fname + lname;
Console.WriteLine("Full Name: {0}", fullname);
//by using string constructor { 'H', 'e', 'l', 'l','o' };
string greetings = new string(letters);
Console.WriteLine("Greetings: {0}", greetings);
//methods returning string { "Hello", "From", "Tutorials", "Point" };
string message = String.Join(" ", sarray);
Console.WriteLine("Message: {0}", message);
//formatting method to convert a value
DateTime waiting = new DateTime(2012, 10, 10, 17, 58, 1);
string chat = String.Format("Message sent at {0:t} on {0:D}", waiting);
Console.WriteLine("Message: {0}", chat);
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Full Name: RowanAtkinson
Greetings: Hello
Message: Hello From Tutorials Point
Message: Message sent at 5:58 PM on Wednesday, October 10, 2012
Proprietà della classe String
La classe String ha le seguenti due proprietà:
Sr.No. | Proprietà e descrizione |
---|---|
1 | Chars Ottiene l' oggetto Char in una posizione specificata nell'oggetto String corrente . |
2 | Length Ottiene il numero di caratteri nell'oggetto String corrente. |
Metodi della classe String
La classe String ha numerosi metodi che ti aiutano a lavorare con gli oggetti stringa. La tabella seguente fornisce alcuni dei metodi più comunemente utilizzati:
Sr.No. | Metodi e descrizione |
---|---|
1 | public static int Compare(string strA, string strB) Confronta due oggetti stringa specificati e restituisce un numero intero che indica la loro posizione relativa nell'ordinamento. |
2 | public static int Compare(string strA, string strB, bool ignoreCase ) Confronta due oggetti stringa specificati e restituisce un numero intero che indica la loro posizione relativa nell'ordinamento. Tuttavia, ignora maiuscole e minuscole se il parametro booleano è vero. |
3 | public static string Concat(string str0, string str1) Concatena due oggetti stringa. |
4 | public static string Concat(string str0, string str1, string str2) Concatena tre oggetti stringa. |
5 | public static string Concat(string str0, string str1, string str2, string str3) Concatena quattro oggetti stringa. |
6 | public bool Contains(string value) Restituisce un valore che indica se l'oggetto String specificato si trova all'interno di questa stringa. |
7 | public static string Copy(string str) Crea un nuovo oggetto String con lo stesso valore della stringa specificata. |
8 | public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) Copia un numero specificato di caratteri da una posizione specificata dell'oggetto String a una posizione specificata in una matrice di caratteri Unicode. |
9 | public bool EndsWith(string value) Determina se la fine dell'oggetto stringa corrisponde alla stringa specificata. |
10 | public bool Equals(string value) Determina se l'oggetto String corrente e l'oggetto String specificato hanno lo stesso valore. |
11 | public static bool Equals(string a, string b) Determina se due oggetti String specificati hanno lo stesso valore. |
12 | public static string Format(string format, Object arg0) Sostituisce uno o più elementi di formato in una stringa specificata con la rappresentazione di stringa di un oggetto specificato. |
13 | public int IndexOf(char value) Restituisce l'indice in base zero della prima occorrenza del carattere Unicode specificato nella stringa corrente. |
14 | public int IndexOf(string value) Restituisce l'indice in base zero della prima occorrenza della stringa specificata in questa istanza. |
15 | public int IndexOf(char value, int startIndex) Restituisce l'indice in base zero della prima occorrenza del carattere Unicode specificato in questa stringa, iniziando la ricerca nella posizione del carattere specificata. |
16 | public int IndexOf(string value, int startIndex) Restituisce l'indice in base zero della prima occorrenza della stringa specificata in questa istanza, iniziando la ricerca dalla posizione del carattere specificata. |
17 | public int IndexOfAny(char[] anyOf) Restituisce l'indice in base zero della prima occorrenza in questa istanza di qualsiasi carattere in una matrice specificata di caratteri Unicode. |
18 | public int IndexOfAny(char[] anyOf, int startIndex) Restituisce l'indice in base zero della prima occorrenza in questa istanza di qualsiasi carattere in una matrice specificata di caratteri Unicode, iniziando la ricerca dalla posizione del carattere specificata. |
19 | public string Insert(int startIndex, string value) Restituisce una nuova stringa in cui una stringa specificata viene inserita in una posizione di indice specificata nell'oggetto stringa corrente. |
20 | public static bool IsNullOrEmpty(string value) Indica se la stringa specificata è null o una stringa vuota. |
21 | public static string Join(string separator, params string[] value) Concatena tutti gli elementi di una matrice di stringhe, utilizzando il separatore specificato tra ogni elemento. |
22 | public static string Join(string separator, string[] value, int startIndex, int count) Concatena gli elementi specificati di una matrice di stringhe, utilizzando il separatore specificato tra ogni elemento. |
23 | public int LastIndexOf(char value) Restituisce la posizione dell'indice in base zero dell'ultima occorrenza del carattere Unicode specificato all'interno dell'oggetto stringa corrente. |
24 | public int LastIndexOf(string value) Restituisce la posizione dell'indice in base zero dell'ultima occorrenza di una stringa specificata all'interno dell'oggetto stringa corrente. |
25 | public string Remove(int startIndex) Rimuove tutti i caratteri nell'istanza corrente, iniziando da una posizione specificata e proseguendo fino all'ultima posizione, e restituisce la stringa. |
26 | public string Remove(int startIndex, int count) Rimuove il numero di caratteri specificato nella stringa corrente a partire da una posizione specificata e restituisce la stringa. |
27 | public string Replace(char oldChar, char newChar) Sostituisce tutte le occorrenze di un carattere Unicode specificato nell'oggetto stringa corrente con il carattere Unicode specificato e restituisce la nuova stringa. |
28 | public string Replace(string oldValue, string newValue) Sostituisce tutte le occorrenze di una stringa specificata nell'oggetto stringa corrente con la stringa specificata e restituisce la nuova stringa. |
29 | public string[] Split(params char[] separator) Restituisce una matrice di stringhe che contiene le sottostringhe nell'oggetto stringa corrente, delimitata da elementi di una matrice di caratteri Unicode specificata. |
30 | public string[] Split(char[] separator, int count) Restituisce una matrice di stringhe che contiene le sottostringhe nell'oggetto stringa corrente, delimitata da elementi di una matrice di caratteri Unicode specificata. Il parametro int specifica il numero massimo di sottostringhe da restituire. |
31 | public bool StartsWith(string value) Determina se l'inizio di questa istanza di stringa corrisponde alla stringa specificata. |
32 | public char[] ToCharArray() Restituisce una matrice di caratteri Unicode con tutti i caratteri nell'oggetto stringa corrente. |
33 | public char[] ToCharArray(int startIndex, int length) Restituisce una matrice di caratteri Unicode con tutti i caratteri nell'oggetto stringa corrente, a partire dall'indice specificato e fino alla lunghezza specificata. |
34 | public string ToLower() Restituisce una copia di questa stringa convertita in minuscolo. |
35 | public string ToUpper() Restituisce una copia di questa stringa convertita in maiuscolo. |
36 | public string Trim() Rimuove tutti i caratteri di spazio vuoto iniziali e finali dall'oggetto String corrente. |
È possibile visitare la libreria MSDN per l'elenco completo dei metodi e dei costruttori di classi String.
Esempi
L'esempio seguente mostra alcuni dei metodi sopra menzionati:
Confronto di stringhe
using System;
namespace StringApplication {
class StringProg {
static void Main(string[] args) {
string str1 = "This is test";
string str2 = "This is text";
if (String.Compare(str1, str2) == 0) {
Console.WriteLine(str1 + " and " + str2 + " are equal.");
} else {
Console.WriteLine(str1 + " and " + str2 + " are not equal.");
}
Console.ReadKey() ;
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
This is test and This is text are not equal.
String Contiene String
using System;
namespace StringApplication {
class StringProg {
static void Main(string[] args) {
string str = "This is test";
if (str.Contains("test")) {
Console.WriteLine("The sequence 'test' was found.");
}
Console.ReadKey() ;
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
The sequence 'test' was found.
Ottenere una sottostringa
using System;
namespace StringApplication {
class StringProg {
static void Main(string[] args) {
string str = "Last night I dreamt of San Pedro";
Console.WriteLine(str);
string substr = str.Substring(23);
Console.WriteLine(substr);
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
San Pedro
Unire le stringhe
using System;
namespace StringApplication {
class StringProg {
static void Main(string[] args) {
string[] starray = new string[]{"Down the way nights are dark",
"And the sun shines daily on the mountain top",
"I took a trip on a sailing ship",
"And when I reached Jamaica",
"I made a stop"};
string str = String.Join("\n", starray);
Console.WriteLine(str);
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Down the way nights are dark
And the sun shines daily on the mountain top
I took a trip on a sailing ship
And when I reached Jamaica
I made a stop
In C #, una struttura è un tipo di dati di tipo valore. Ti aiuta a fare in modo che una singola variabile conservi i dati correlati di vari tipi di dati. Ilstruct la parola chiave viene utilizzata per creare una struttura.
Le strutture vengono utilizzate per rappresentare un record. Supponi di voler tenere traccia dei tuoi libri in una biblioteca. Potresti voler monitorare i seguenti attributi di ogni libro:
- Title
- Author
- Subject
- ID libro
Definizione di una struttura
Per definire una struttura, è necessario utilizzare l'istruzione struct. L'istruzione struct definisce un nuovo tipo di dati, con più di un membro per il programma.
Ad esempio, ecco come puoi dichiarare la struttura del libro:
struct Books {
public string title;
public string author;
public string subject;
public int book_id;
};
Il seguente programma mostra l'utilizzo della struttura:
using System;
struct Books {
public string title;
public string author;
public string subject;
public int book_id;
};
public class testStructure {
public static void Main(string[] args) {
Books Book1; /* Declare Book1 of type Book */
Books Book2; /* Declare Book2 of type Book */
/* book 1 specification */
Book1.title = "C Programming";
Book1.author = "Nuha Ali";
Book1.subject = "C Programming Tutorial";
Book1.book_id = 6495407;
/* book 2 specification */
Book2.title = "Telecom Billing";
Book2.author = "Zara Ali";
Book2.subject = "Telecom Billing Tutorial";
Book2.book_id = 6495700;
/* print Book1 info */
Console.WriteLine( "Book 1 title : {0}", Book1.title);
Console.WriteLine("Book 1 author : {0}", Book1.author);
Console.WriteLine("Book 1 subject : {0}", Book1.subject);
Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);
/* print Book2 info */
Console.WriteLine("Book 2 title : {0}", Book2.title);
Console.WriteLine("Book 2 author : {0}", Book2.author);
Console.WriteLine("Book 2 subject : {0}", Book2.subject);
Console.WriteLine("Book 2 book_id : {0}", Book2.book_id);
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700
Funzionalità di strutture C #
Hai già utilizzato una struttura semplice denominata Libri. Le strutture in C # sono molto diverse da quelle in C o C ++ tradizionali. Le strutture C # hanno le seguenti caratteristiche:
Le strutture possono avere metodi, campi, indicizzatori, proprietà, metodi operatore ed eventi.
Le strutture possono avere costruttori definiti, ma non distruttori. Tuttavia, non è possibile definire un costruttore predefinito per una struttura. Il costruttore predefinito viene definito automaticamente e non può essere modificato.
A differenza delle classi, le strutture non possono ereditare altre strutture o classi.
Le strutture non possono essere utilizzate come base per altre strutture o classi.
Una struttura può implementare una o più interfacce.
I membri della struttura non possono essere specificati come astratti, virtuali o protetti.
Quando crei un oggetto struct usando il Newoperatore, viene creato e viene chiamato il costruttore appropriato. A differenza delle classi, le strutture possono essere istanziate senza utilizzare l'operatore New.
Se l'operatore Nuovo non viene utilizzato, i campi rimangono non assegnati e l'oggetto non può essere utilizzato fino a quando tutti i campi non vengono inizializzati.
Classe contro struttura
Le classi e le strutture presentano le seguenti differenze di base:
- le classi sono tipi di riferimento e le strutture sono tipi di valore
- le strutture non supportano l'ereditarietà
- le strutture non possono avere un costruttore predefinito
Alla luce delle discussioni precedenti, riscriviamo l'esempio precedente:
using System;
struct Books {
private string title;
private string author;
private string subject;
private int book_id;
public void getValues(string t, string a, string s, int id) {
title = t;
author = a;
subject = s;
book_id = id;
}
public void display() {
Console.WriteLine("Title : {0}", title);
Console.WriteLine("Author : {0}", author);
Console.WriteLine("Subject : {0}", subject);
Console.WriteLine("Book_id :{0}", book_id);
}
};
public class testStructure {
public static void Main(string[] args) {
Books Book1 = new Books(); /* Declare Book1 of type Book */
Books Book2 = new Books(); /* Declare Book2 of type Book */
/* book 1 specification */
Book1.getValues("C Programming",
"Nuha Ali", "C Programming Tutorial",6495407);
/* book 2 specification */
Book2.getValues("Telecom Billing",
"Zara Ali", "Telecom Billing Tutorial", 6495700);
/* print Book1 info */
Book1.display();
/* print Book2 info */
Book2.display();
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Title : C Programming
Author : Nuha Ali
Subject : C Programming Tutorial
Book_id : 6495407
Title : Telecom Billing
Author : Zara Ali
Subject : Telecom Billing Tutorial
Book_id : 6495700
Un'enumerazione è un insieme di costanti intere denominate. Un tipo enumerato viene dichiarato utilizzando ilenum parola chiave.
Le enumerazioni C # sono tipo di dati valore. In altre parole, l'enumerazione contiene i propri valori e non può ereditare o non può trasmettere l'ereditarietà.
Dichiarazione della variabile enum
La sintassi generale per dichiarare un'enumerazione è:
enum <enum_name> {
enumeration list
};
Dove,
L'enum_name specifica il nome del tipo di enumerazione.
L' elenco di enumerazione è un elenco di identificatori separati da virgole.
Ciascuno dei simboli nell'elenco di enumerazione rappresenta un valore intero, uno maggiore del simbolo che lo precede. Per impostazione predefinita, il valore del primo simbolo di enumerazione è 0. Ad esempio:
enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
Esempio
L'esempio seguente mostra l'uso della variabile enum -
using System;
namespace EnumApplication {
class EnumProgram {
enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
static void Main(string[] args) {
int WeekdayStart = (int)Days.Mon;
int WeekdayEnd = (int)Days.Fri;
Console.WriteLine("Monday: {0}", WeekdayStart);
Console.WriteLine("Friday: {0}", WeekdayEnd);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Monday: 1
Friday: 5
Quando si definisce una classe, si definisce un progetto per un tipo di dati. Questo in realtà non definisce alcun dato, ma definisce il significato del nome della classe. Cioè, in cosa consiste un oggetto della classe e quali operazioni possono essere eseguite su quell'oggetto. Gli oggetti sono istanze di una classe. I metodi e le variabili che costituiscono una classe sono chiamati membri della classe.
Definizione di una classe
Una definizione di classe inizia con la parola chiave class seguita dal nome della classe; e il corpo di classe racchiuso da un paio di parentesi graffe. Di seguito è riportata la forma generale di una definizione di classe:
<access specifier> class class_name {
// member variables
<access specifier> <data type> variable1;
<access specifier> <data type> variable2;
...
<access specifier> <data type> variableN;
// member methods
<access specifier> <return type> method1(parameter_list) {
// method body
}
<access specifier> <return type> method2(parameter_list) {
// method body
}
...
<access specifier> <return type> methodN(parameter_list) {
// method body
}
}
Nota -
Gli specificatori di accesso specificano le regole di accesso per i membri e per la classe stessa. Se non menzionato, lo specificatore di accesso predefinito per un tipo di classe èinternal. L'accesso predefinito per i membri èprivate.
Il tipo di dati specifica il tipo di variabile e il tipo restituito specifica il tipo di dati dei dati restituiti dal metodo, se presente.
Per accedere ai membri della classe, utilizzare l'operatore punto (.).
L'operatore punto collega il nome di un oggetto con il nome di un membro.
Il seguente esempio illustra i concetti discussi finora:
using System;
namespace BoxApplication {
class Box {
public double length; // Length of a box
public double breadth; // Breadth of a box
public double height; // Height of a box
}
class Boxtester {
static void Main(string[] args) {
Box Box1 = new Box(); // Declare Box1 of type Box
Box Box2 = new Box(); // Declare Box2 of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.height = 5.0;
Box1.length = 6.0;
Box1.breadth = 7.0;
// box 2 specification
Box2.height = 10.0;
Box2.length = 12.0;
Box2.breadth = 13.0;
// volume of box 1
volume = Box1.height * Box1.length * Box1.breadth;
Console.WriteLine("Volume of Box1 : {0}", volume);
// volume of box 2
volume = Box2.height * Box2.length * Box2.breadth;
Console.WriteLine("Volume of Box2 : {0}", volume);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Volume of Box1 : 210
Volume of Box2 : 1560
Funzioni membro e incapsulamento
Una funzione membro di una classe è una funzione che ha la sua definizione o il suo prototipo all'interno della definizione di classe simile a qualsiasi altra variabile. Funziona su qualsiasi oggetto della classe di cui è membro e ha accesso a tutti i membri di una classe per quell'oggetto.
Le variabili membro sono gli attributi di un oggetto (dal punto di vista della progettazione) e vengono mantenute private per implementare l'incapsulamento. È possibile accedere a queste variabili solo utilizzando le funzioni membro pubbliche.
Mettiamo i concetti sopra per impostare e ottenere il valore dei diversi membri della classe in una classe -
using System;
namespace BoxApplication {
class Box {
private double length; // Length of a box
private double breadth; // Breadth of a box
private double height; // Height of a box
public void setLength( double len ) {
length = len;
}
public void setBreadth( double bre ) {
breadth = bre;
}
public void setHeight( double hei ) {
height = hei;
}
public double getVolume() {
return length * breadth * height;
}
}
class Boxtester {
static void Main(string[] args) {
Box Box1 = new Box(); // Declare Box1 of type Box
Box Box2 = new Box();
double volume;
// Declare Box2 of type Box
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
volume = Box1.getVolume();
Console.WriteLine("Volume of Box1 : {0}" ,volume);
// volume of box 2
volume = Box2.getVolume();
Console.WriteLine("Volume of Box2 : {0}", volume);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Volume of Box1 : 210
Volume of Box2 : 1560
Costruttori C #
Una classe constructor è una funzione membro speciale di una classe che viene eseguita ogni volta che creiamo nuovi oggetti di quella classe.
Un costruttore ha esattamente lo stesso nome di quello della classe e non ha alcun tipo di ritorno. L'esempio seguente spiega il concetto di costruttore:
using System;
namespace LineApplication {
class Line {
private double length; // Length of a line
public Line() {
Console.WriteLine("Object is being created");
}
public void setLength( double len ) {
length = len;
}
public double getLength() {
return length;
}
static void Main(string[] args) {
Line line = new Line();
// set line length
line.setLength(6.0);
Console.WriteLine("Length of line : {0}", line.getLength());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Object is being created
Length of line : 6
UN default constructornon ha alcun parametro ma, se necessario, un costruttore può avere parametri. Tali costruttori sono chiamatiparameterized constructors. Questa tecnica ti aiuta ad assegnare il valore iniziale a un oggetto al momento della sua creazione come mostrato nell'esempio seguente:
using System;
namespace LineApplication {
class Line {
private double length; // Length of a line
public Line(double len) { //Parameterized constructor
Console.WriteLine("Object is being created, length = {0}", len);
length = len;
}
public void setLength( double len ) {
length = len;
}
public double getLength() {
return length;
}
static void Main(string[] args) {
Line line = new Line(10.0);
Console.WriteLine("Length of line : {0}", line.getLength());
// set line length
line.setLength(6.0);
Console.WriteLine("Length of line : {0}", line.getLength());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Object is being created, length = 10
Length of line : 10
Length of line : 6
Distruttori C #
UN destructorè una funzione membro speciale di una classe che viene eseguita ogni volta che un oggetto della sua classe esce dall'ambito. UNdestructor ha esattamente lo stesso nome di quello della classe con una tilde prefissata (~) e non può né restituire un valore né accettare alcun parametro.
Il distruttore può essere molto utile per rilasciare le risorse di memoria prima di uscire dal programma. I distruttori non possono essere ereditati o sovraccaricati.
L'esempio seguente spiega il concetto di distruttore:
using System;
namespace LineApplication {
class Line {
private double length; // Length of a line
public Line() { // constructor
Console.WriteLine("Object is being created");
}
~Line() { //destructor
Console.WriteLine("Object is being deleted");
}
public void setLength( double len ) {
length = len;
}
public double getLength() {
return length;
}
static void Main(string[] args) {
Line line = new Line();
// set line length
line.setLength(6.0);
Console.WriteLine("Length of line : {0}", line.getLength());
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Object is being created
Length of line : 6
Object is being deleted
Membri statici di una classe C #
Possiamo definire i membri della classe come statici usando staticparola chiave. Quando dichiariamo un membro di una classe come statico, significa che non importa quanti oggetti della classe vengono creati, c'è solo una copia del membro statico.
La parola chiave staticimplica che esiste solo un'istanza del membro per una classe. Le variabili statiche vengono utilizzate per definire le costanti perché i loro valori possono essere recuperati richiamando la classe senza crearne un'istanza. Le variabili statiche possono essere inizializzate al di fuori della funzione membro o della definizione di classe. È inoltre possibile inizializzare le variabili statiche all'interno della definizione della classe.
L'esempio seguente mostra l'uso di static variables -
using System;
namespace StaticVarApplication {
class StaticVar {
public static int num;
public void count() {
num++;
}
public int getNum() {
return num;
}
}
class StaticTester {
static void Main(string[] args) {
StaticVar s1 = new StaticVar();
StaticVar s2 = new StaticVar();
s1.count();
s1.count();
s1.count();
s2.count();
s2.count();
s2.count();
Console.WriteLine("Variable num for s1: {0}", s1.getNum());
Console.WriteLine("Variable num for s2: {0}", s2.getNum());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Variable num for s1: 6
Variable num for s2: 6
Puoi anche dichiarare un file member function come static. Tali funzioni possono accedere solo a variabili statiche. Le funzioni statiche esistono anche prima che l'oggetto venga creato. L'esempio seguente mostra l'uso distatic functions -
using System;
namespace StaticVarApplication {
class StaticVar {
public static int num;
public void count() {
num++;
}
public static int getNum() {
return num;
}
}
class StaticTester {
static void Main(string[] args) {
StaticVar s = new StaticVar();
s.count();
s.count();
s.count();
Console.WriteLine("Variable num: {0}", StaticVar.getNum());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Variable num: 3
Uno dei concetti più importanti nella programmazione orientata agli oggetti è l'ereditarietà. L'ereditarietà ci consente di definire una classe in termini di un'altra classe, il che semplifica la creazione e la manutenzione di un'applicazione. Ciò offre anche l'opportunità di riutilizzare la funzionalità del codice e accelera i tempi di implementazione.
Quando si crea una classe, invece di scrivere membri dati e funzioni membro completamente nuovi, il programmatore può designare che la nuova classe erediti i membri di una classe esistente. Questa classe esistente è chiamatabase class e la nuova classe è indicata come derived classe.
L'idea di eredità implementa il IS-Arelazione. Ad esempio, mammiferoIS A animale, cane IS-A mammifero quindi cane IS-A anche animali, e così via.
Classi di base e derivate
Una classe può essere derivata da più di una classe o interfaccia, il che significa che può ereditare dati e funzioni da più classi o interfacce di base.
La sintassi utilizzata in C # per la creazione di classi derivate è la seguente:
<acess-specifier> class <base_class> {
...
}
class <derived_class> : <base_class> {
...
}
Considera una classe di base Shape e la sua classe derivata Rectangle -
using System;
namespace InheritanceApplication {
class Shape {
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
protected int width;
protected int height;
}
// Derived class
class Rectangle: Shape {
public int getArea() {
return (width * height);
}
}
class RectangleTester {
static void Main(string[] args) {
Rectangle Rect = new Rectangle();
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
Console.WriteLine("Total area: {0}", Rect.getArea());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Total area: 35
Inizializzazione della classe di base
La classe derivata eredita le variabili del membro della classe base ei metodi del membro. Pertanto l'oggetto della super classe dovrebbe essere creato prima della creazione della sottoclasse. È possibile fornire istruzioni per l'inizializzazione della superclasse nell'elenco di inizializzazione dei membri.
Il seguente programma lo dimostra:
using System;
namespace RectangleApplication {
class Rectangle {
//member variables
protected double length;
protected double width;
public Rectangle(double l, double w) {
length = l;
width = w;
}
public double GetArea() {
return length * width;
}
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class Tabletop : Rectangle {
private double cost;
public Tabletop(double l, double w) : base(l, w) { }
public double GetCost() {
double cost;
cost = GetArea() * 70;
return cost;
}
public void Display() {
base.Display();
Console.WriteLine("Cost: {0}", GetCost());
}
}
class ExecuteRectangle {
static void Main(string[] args) {
Tabletop t = new Tabletop(4.5, 7.5);
t.Display();
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Length: 4.5
Width: 7.5
Area: 33.75
Cost: 2362.5
Ereditarietà multipla in C #
C# does not support multiple inheritance. Tuttavia, è possibile utilizzare le interfacce per implementare più ereditarietà. Il seguente programma lo dimostra:
using System;
namespace InheritanceApplication {
class Shape {
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
protected int width;
protected int height;
}
// Base class PaintCost
public interface PaintCost {
int getCost(int area);
}
// Derived class
class Rectangle : Shape, PaintCost {
public int getArea() {
return (width * height);
}
public int getCost(int area) {
return area * 70;
}
}
class RectangleTester {
static void Main(string[] args) {
Rectangle Rect = new Rectangle();
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// Print the area of the object.
Console.WriteLine("Total area: {0}", Rect.getArea());
Console.WriteLine("Total paint cost: ${0}" , Rect.getCost(area));
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Total area: 35
Total paint cost: $2450
La parola polymorphismsignifica avere molte forme. Nel paradigma della programmazione orientata agli oggetti, il polimorfismo è spesso espresso come "un'interfaccia, più funzioni".
Il polimorfismo può essere statico o dinamico. Instatic polymorphism, la risposta a una funzione viene determinata in fase di compilazione. Indynamic polymorphism, viene deciso in fase di esecuzione.
Polimorfismo statico
Il meccanismo di collegamento di una funzione con un oggetto durante la fase di compilazione è chiamato associazione anticipata. È anche chiamato binding statico. C # fornisce due tecniche per implementare il polimorfismo statico. Sono -
- Sovraccarico delle funzioni
- Sovraccarico dell'operatore
Discuteremo il sovraccarico degli operatori nel prossimo capitolo.
Funzione sovraccarico
È possibile avere più definizioni per lo stesso nome di funzione nello stesso ambito. La definizione della funzione deve differire l'una dall'altra per i tipi e / o il numero di argomenti nell'elenco degli argomenti. Non è possibile eseguire l'overload di dichiarazioni di funzione che differiscono solo per il tipo restituito.
L'esempio seguente mostra l'utilizzo di function print() per stampare diversi tipi di dati -
using System;
namespace PolymorphismApplication {
class Printdata {
void print(int i) {
Console.WriteLine("Printing int: {0}", i );
}
void print(double f) {
Console.WriteLine("Printing float: {0}" , f);
}
void print(string s) {
Console.WriteLine("Printing string: {0}", s);
}
static void Main(string[] args) {
Printdata p = new Printdata();
// Call print to print integer
p.print(5);
// Call print to print float
p.print(500.263);
// Call print to print string
p.print("Hello C++");
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Printing int: 5
Printing float: 500.263
Printing string: Hello C++
Polimorfismo dinamico
C # consente di creare classi astratte utilizzate per fornire un'implementazione parziale della classe di un'interfaccia. L'implementazione è completata quando una classe derivata eredita da essa.Abstractle classi contengono metodi astratti, che vengono implementati dalla classe derivata. Le classi derivate hanno funzionalità più specializzate.
Ecco le regole sulle classi astratte:
Non è possibile creare un'istanza di una classe astratta
Non è possibile dichiarare un metodo astratto al di fuori di una classe astratta
Quando viene dichiarata una classe sealed, non può essere ereditato, le classi astratte non possono essere dichiarate sigillate.
Il seguente programma mostra una classe astratta:
using System;
namespace PolymorphismApplication {
abstract class Shape {
public abstract int area();
}
class Rectangle: Shape {
private int length;
private int width;
public Rectangle( int a = 0, int b = 0) {
length = a;
width = b;
}
public override int area () {
Console.WriteLine("Rectangle class area :");
return (width * length);
}
}
class RectangleTester {
static void Main(string[] args) {
Rectangle r = new Rectangle(10, 7);
double a = r.area();
Console.WriteLine("Area: {0}",a);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Rectangle class area :
Area: 70
Quando si dispone di una funzione definita in una classe che si desidera implementare in una o più classi ereditate, si utilizza virtualfunzioni. Le funzioni virtuali potrebbero essere implementate in modo diverso in diverse classi ereditate e la chiamata a queste funzioni verrà decisa in fase di esecuzione.
Il polimorfismo dinamico è implementato da abstract classes e virtual functions.
Il seguente programma lo dimostra:
using System;
namespace PolymorphismApplication {
class Shape {
protected int width, height;
public Shape( int a = 0, int b = 0) {
width = a;
height = b;
}
public virtual int area() {
Console.WriteLine("Parent class area :");
return 0;
}
}
class Rectangle: Shape {
public Rectangle( int a = 0, int b = 0): base(a, b) {
}
public override int area () {
Console.WriteLine("Rectangle class area :");
return (width * height);
}
}
class Triangle: Shape {
public Triangle(int a = 0, int b = 0): base(a, b) {
}
public override int area() {
Console.WriteLine("Triangle class area :");
return (width * height / 2);
}
}
class Caller {
public void CallArea(Shape sh) {
int a;
a = sh.area();
Console.WriteLine("Area: {0}", a);
}
}
class Tester {
static void Main(string[] args) {
Caller c = new Caller();
Rectangle r = new Rectangle(10, 7);
Triangle t = new Triangle(10, 5);
c.CallArea(r);
c.CallArea(t);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Rectangle class area:
Area: 70
Triangle class area:
Area: 25
È possibile ridefinire o sovraccaricare la maggior parte degli operatori incorporati disponibili in C #. Pertanto un programmatore può utilizzare anche operatori con tipi definiti dall'utente. Gli operatori sovraccaricati sono funzioni con nomi speciali la parola chiaveoperatorseguito dal simbolo dell'operatore da definire. simile a qualsiasi altra funzione, un operatore sovraccarico ha un tipo restituito e un elenco di parametri.
Ad esempio, passa attraverso la seguente funzione:
public static Box operator+ (Box b, Box c) {
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
La funzione precedente implementa l'operatore di addizione (+) per una classe Box definita dall'utente. Aggiunge gli attributi di due oggetti Box e restituisce l'oggetto Box risultante.
Implementazione del sovraccarico dell'operatore
Il seguente programma mostra l'implementazione completa:
using System;
namespace OperatorOvlApplication {
class Box {
private double length; // Length of a box
private double breadth; // Breadth of a box
private double height; // Height of a box
public double getVolume() {
return length * breadth * height;
}
public void setLength( double len ) {
length = len;
}
public void setBreadth( double bre ) {
breadth = bre;
}
public void setHeight( double hei ) {
height = hei;
}
// Overload + operator to add two Box objects.
public static Box operator+ (Box b, Box c) {
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
}
class Tester {
static void Main(string[] args) {
Box Box1 = new Box(); // Declare Box1 of type Box
Box Box2 = new Box(); // Declare Box2 of type Box
Box Box3 = new Box(); // Declare Box3 of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
volume = Box1.getVolume();
Console.WriteLine("Volume of Box1 : {0}", volume);
// volume of box 2
volume = Box2.getVolume();
Console.WriteLine("Volume of Box2 : {0}", volume);
// Add two object as follows:
Box3 = Box1 + Box2;
// volume of box 3
volume = Box3.getVolume();
Console.WriteLine("Volume of Box3 : {0}", volume);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
Operatori sovraccaricabili e non sovraccaricabili
La tabella seguente descrive la capacità di sovraccarico degli operatori in C # -
Sr.No. | Operatori e descrizione |
---|---|
1 | +, -, !, ~, ++, -- Questi operatori unari accettano un operando e possono essere sovraccaricati. |
2 | +, -, *, /, % Questi operatori binari accettano un operando e possono essere sovraccaricati. |
3 | ==, !=, <, >, <=, >= Gli operatori di confronto possono essere sovraccaricati. |
4 | &&, || Gli operatori logici condizionali non possono essere sovraccaricati direttamente. |
5 | +=, -=, *=, /=, %= Gli operatori di assegnazione non possono essere sovraccaricati. |
6 | =, ., ?:, ->, new, is, sizeof, typeof Questi operatori non possono essere sovraccaricati. |
Esempio
Alla luce delle discussioni precedenti, estendiamo l'esempio precedente e sovraccarichiamo pochi altri operatori:
using System;
namespace OperatorOvlApplication {
class Box {
private double length; // Length of a box
private double breadth; // Breadth of a box
private double height; // Height of a box
public double getVolume() {
return length * breadth * height;
}
public void setLength( double len ) {
length = len;
}
public void setBreadth( double bre ) {
breadth = bre;
}
public void setHeight( double hei ) {
height = hei;
}
// Overload + operator to add two Box objects.
public static Box operator+ (Box b, Box c) {
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
public static bool operator == (Box lhs, Box rhs) {
bool status = false;
if (lhs.length == rhs.length && lhs.height == rhs.height && lhs.breadth == rhs.breadth) {
status = true;
}
return status;
}
public static bool operator !=(Box lhs, Box rhs) {
bool status = false;
if (lhs.length != rhs.length || lhs.height != rhs.height || lhs.breadth != rhs.breadth) {
status = true;
}
return status;
}
public static bool operator <(Box lhs, Box rhs) {
bool status = false;
if (lhs.length < rhs.length && lhs.height < rhs.height && lhs.breadth < rhs.breadth) {
status = true;
}
return status;
}
public static bool operator >(Box lhs, Box rhs) {
bool status = false;
if (lhs.length > rhs.length && lhs.height > rhs.height && lhs.breadth > rhs.breadth) {
status = true;
}
return status;
}
public static bool operator <=(Box lhs, Box rhs) {
bool status = false;
if (lhs.length <= rhs.length && lhs.height <= rhs.height && lhs.breadth <= rhs.breadth) {
status = true;
}
return status;
}
public static bool operator >=(Box lhs, Box rhs) {
bool status = false;
if (lhs.length >= rhs.length && lhs.height >= rhs.height && lhs.breadth >= rhs.breadth) {
status = true;
}
return status;
}
public override string ToString() {
return String.Format("({0}, {1}, {2})", length, breadth, height);
}
}
class Tester {
static void Main(string[] args) {
Box Box1 = new Box(); // Declare Box1 of type Box
Box Box2 = new Box(); // Declare Box2 of type Box
Box Box3 = new Box(); // Declare Box3 of type Box
Box Box4 = new Box();
double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
//displaying the Boxes using the overloaded ToString():
Console.WriteLine("Box 1: {0}", Box1.ToString());
Console.WriteLine("Box 2: {0}", Box2.ToString());
// volume of box 1
volume = Box1.getVolume();
Console.WriteLine("Volume of Box1 : {0}", volume);
// volume of box 2
volume = Box2.getVolume();
Console.WriteLine("Volume of Box2 : {0}", volume);
// Add two object as follows:
Box3 = Box1 + Box2;
Console.WriteLine("Box 3: {0}", Box3.ToString());
// volume of box 3
volume = Box3.getVolume();
Console.WriteLine("Volume of Box3 : {0}", volume);
//comparing the boxes
if (Box1 > Box2)
Console.WriteLine("Box1 is greater than Box2");
else
Console.WriteLine("Box1 is greater than Box2");
if (Box1 < Box2)
Console.WriteLine("Box1 is less than Box2");
else
Console.WriteLine("Box1 is not less than Box2");
if (Box1 >= Box2)
Console.WriteLine("Box1 is greater or equal to Box2");
else
Console.WriteLine("Box1 is not greater or equal to Box2");
if (Box1 <= Box2)
Console.WriteLine("Box1 is less or equal to Box2");
else
Console.WriteLine("Box1 is not less or equal to Box2");
if (Box1 != Box2)
Console.WriteLine("Box1 is not equal to Box2");
else
Console.WriteLine("Box1 is not greater or equal to Box2");
Box4 = Box3;
if (Box3 == Box4)
Console.WriteLine("Box3 is equal to Box4");
else
Console.WriteLine("Box3 is not equal to Box4");
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Box 1: (6, 7, 5)
Box 2: (12, 13, 10)
Volume of Box1 : 210
Volume of Box2 : 1560
Box 3: (18, 20, 15)
Volume of Box3 : 5400
Box1 is not greater than Box2
Box1 is less than Box2
Box1 is not greater or equal to Box2
Box1 is less or equal to Box2
Box1 is not equal to Box2
Box3 is equal to Box4
Un'interfaccia è definita come un contratto sintattico che tutte le classi che ereditano l'interfaccia dovrebbero seguire. L'interfaccia definisce il'what' parte del contratto sintattico e le classi derivate definiscono il 'how' parte del contratto sintattico.
Le interfacce definiscono proprietà, metodi ed eventi, che sono i membri dell'interfaccia. Le interfacce contengono solo la dichiarazione dei membri. È responsabilità della classe derivante definire i membri. Spesso aiuta a fornire una struttura standard che le classi derivate seguirebbero.
Le classi astratte in una certa misura servono allo stesso scopo, tuttavia, vengono utilizzate principalmente quando solo pochi metodi devono essere dichiarati dalla classe base e la classe derivante implementa le funzionalità.
Dichiarazione di interfacce
Le interfacce vengono dichiarate utilizzando la parola chiave interface. È simile alla dichiarazione di classe. Le istruzioni dell'interfaccia sono pubbliche per impostazione predefinita. Di seguito è riportato un esempio di una dichiarazione di interfaccia:
public interface ITransactions {
// interface members
void showTransaction();
double getAmount();
}
Esempio
L'esempio seguente mostra l'implementazione dell'interfaccia precedente:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
namespace InterfaceApplication {
public interface ITransactions {
// interface members
void showTransaction();
double getAmount();
}
public class Transaction : ITransactions {
private string tCode;
private string date;
private double amount;
public Transaction() {
tCode = " ";
date = " ";
amount = 0.0;
}
public Transaction(string c, string d, double a) {
tCode = c;
date = d;
amount = a;
}
public double getAmount() {
return amount;
}
public void showTransaction() {
Console.WriteLine("Transaction: {0}", tCode);
Console.WriteLine("Date: {0}", date);
Console.WriteLine("Amount: {0}", getAmount());
}
}
class Tester {
static void Main(string[] args) {
Transaction t1 = new Transaction("001", "8/10/2012", 78900.00);
Transaction t2 = new Transaction("002", "9/10/2012", 451900.00);
t1.showTransaction();
t2.showTransaction();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Transaction: 001
Date: 8/10/2012
Amount: 78900
Transaction: 002
Date: 9/10/2012
Amount: 451900
UN namespaceè progettato per fornire un modo per mantenere un insieme di nomi separato da un altro. I nomi delle classi dichiarati in uno spazio dei nomi non sono in conflitto con gli stessi nomi delle classi dichiarati in un altro.
Definizione di uno spazio dei nomi
Una definizione di spazio dei nomi inizia con la parola chiave namespace seguito dal nome dello spazio dei nomi come segue:
namespace namespace_name {
// code declarations
}
Per chiamare la versione abilitata per lo spazio dei nomi di una funzione o di una variabile, anteponi il nome dello spazio dei nomi come segue:
namespace_name.item_name;
Il seguente programma dimostra l'uso degli spazi dei nomi:
using System;
namespace first_space {
class namespace_cl {
public void func() {
Console.WriteLine("Inside first_space");
}
}
}
namespace second_space {
class namespace_cl {
public void func() {
Console.WriteLine("Inside second_space");
}
}
}
class TestClass {
static void Main(string[] args) {
first_space.namespace_cl fc = new first_space.namespace_cl();
second_space.namespace_cl sc = new second_space.namespace_cl();
fc.func();
sc.func();
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Inside first_space
Inside second_space
La parola chiave utilizzando
Il usingla parola chiave indica che il programma sta utilizzando i nomi nello spazio dei nomi specificato. Ad esempio, stiamo usando ilSystemspazio dei nomi nei nostri programmi. La classe Console è definita lì. Scriviamo solo -
Console.WriteLine ("Hello there");
Avremmo potuto scrivere il nome completo come -
System.Console.WriteLine("Hello there");
Puoi anche evitare di anteporre gli spazi dei nomi con usingdirettiva namespace. Questa direttiva indica al compilatore che il codice successivo utilizza i nomi nello spazio dei nomi specificato. Lo spazio dei nomi è quindi implicito per il codice seguente:
Riscriviamo il nostro esempio precedente, usando la direttiva -
using System;
using first_space;
using second_space;
namespace first_space {
class abc {
public void func() {
Console.WriteLine("Inside first_space");
}
}
}
namespace second_space {
class efg {
public void func() {
Console.WriteLine("Inside second_space");
}
}
}
class TestClass {
static void Main(string[] args) {
abc fc = new abc();
efg sc = new efg();
fc.func();
sc.func();
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Inside first_space
Inside second_space
Spazi dei nomi annidati
È possibile definire uno spazio dei nomi all'interno di un altro spazio dei nomi come segue:
namespace namespace_name1 {
// code declarations
namespace namespace_name2 {
// code declarations
}
}
È possibile accedere ai membri dello spazio dei nomi nidificato utilizzando l'operatore punto (.) Come segue:
using System;
using first_space;
using first_space.second_space;
namespace first_space {
class abc {
public void func() {
Console.WriteLine("Inside first_space");
}
}
namespace second_space {
class efg {
public void func() {
Console.WriteLine("Inside second_space");
}
}
}
}
class TestClass {
static void Main(string[] args) {
abc fc = new abc();
efg sc = new efg();
fc.func();
sc.func();
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Inside first_space
Inside second_space
Le direttive del preprocessore danno istruzioni al compilatore di preelaborare le informazioni prima che inizi la compilazione effettiva.
Tutte le direttive del preprocessore iniziano con # e solo i caratteri spazi bianchi possono apparire prima di una direttiva del preprocessore su una riga. Le direttive del preprocessore non sono istruzioni, quindi non terminano con un punto e virgola (;).
Il compilatore C # non dispone di un preprocessore separato; tuttavia, le direttive vengono elaborate come se ce ne fosse una. In C # le direttive del preprocessore vengono usate per aiutare nella compilazione condizionale. A differenza delle direttive C e C ++, non vengono utilizzate per creare macro. Una direttiva del preprocessore deve essere l'unica istruzione su una riga.
Direttive del preprocessore in C #
La tabella seguente elenca le direttive del preprocessore disponibili in C # -
Sr.No. | Direttiva e descrizione del preprocessore |
---|---|
1 | #define Definisce una sequenza di caratteri, chiamata simbolo. |
2 | #undef Ti permette di indefinire un simbolo. |
3 | #if Consente di testare uno o più simboli per vedere se restituiscono true. |
4 | #else Permette di creare una direttiva condizionale composta, insieme a #if. |
5 | #elif Consente di creare una direttiva condizionale composta. |
6 | #endif Specifica la fine di una direttiva condizionale. |
7 | #line Consente di modificare il numero di riga del compilatore e (facoltativamente) l'output del nome del file per errori e avvisi. |
8 | #error Consente di generare un errore da una posizione specifica nel codice. |
9 | #warning Consente di generare un avviso di livello uno da una posizione specifica nel codice. |
10 | #region Consente di specificare un blocco di codice che è possibile espandere o comprimere quando si utilizza la funzionalità di struttura dell'Editor di codice di Visual Studio. |
11 | #endregion Segna la fine di un blocco #region. |
Il preprocessore #define
La direttiva del preprocessore #define crea costanti simboliche.
#define consente di definire un simbolo in modo tale che, utilizzando il simbolo come espressione passata alla direttiva #if, l'espressione restituisca true. La sua sintassi è la seguente:
#define symbol
Il seguente programma lo illustra:
#define PI
using System;
namespace PreprocessorDAppl {
class Program {
static void Main(string[] args) {
#if (PI)
Console.WriteLine("PI is defined");
#else
Console.WriteLine("PI is not defined");
#endif
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
PI is defined
Direttive condizionali
È possibile utilizzare la direttiva #if per creare una direttiva condizionale. Le direttive condizionali sono utili per testare uno o più simboli per verificare se restituiscono true. Se restituiscono true, il compilatore valuta tutto il codice compreso tra #if e la direttiva successiva.
La sintassi per la direttiva condizionale è -
#if symbol [operator symbol]...
Dove, symbol è il nome del simbolo che vuoi testare. È inoltre possibile utilizzare true e false o anteporre al simbolo l'operatore di negazione.
Il simbolo dell'operatore è l'operatore utilizzato per valutare il simbolo. Gli operatori potrebbero essere uno dei seguenti:
- == (uguaglianza)
- ! = (disuguaglianza)
- && (e)
- || (o)
Puoi anche raggruppare simboli e operatori con parentesi. Le direttive condizionali vengono utilizzate per compilare codice per una build di debug o durante la compilazione per una configurazione specifica. Una direttiva condizionale che inizia con a#if la direttiva deve essere terminata esplicitamente con a #endif direttiva.
Il seguente programma dimostra l'uso di direttive condizionali:
#define DEBUG
#define VC_V10
using System;
public class TestClass {
public static void Main() {
#if (DEBUG && !VC_V10)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && VC_V10)
Console.WriteLine("VC_V10 is defined");
#elif (DEBUG && VC_V10)
Console.WriteLine("DEBUG and VC_V10 are defined");
#else
Console.WriteLine("DEBUG and VC_V10 are not defined");
#endif
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
DEBUG and VC_V10 are defined
UN regular expressionè un modello che potrebbe essere confrontato con un testo di input. Il framework .Net fornisce un motore di espressioni regolari che consente tale corrispondenza. Un modello è costituito da uno o più caratteri letterali, operatori o costrutti.
Costrutti per la definizione di espressioni regolari
Esistono varie categorie di caratteri, operatori e costrutti che consentono di definire espressioni regolari. Fare clic sui collegamenti seguenti per trovare questi costrutti.
Il personaggio fugge
Classi di personaggi
Anchors
Costrutti di raggruppamento
Quantifiers
Costrutti di backreference
Costrutti di alternanza
Substitutions
Costrutti vari
La classe Regex
La classe Regex viene utilizzata per rappresentare un'espressione regolare. Ha i seguenti metodi comunemente usati:
Sr.No. | Metodi e descrizione |
---|---|
1 | public bool IsMatch(string input) Indica se l'espressione regolare specificata nel costruttore Regex trova una corrispondenza in una stringa di input specificata. |
2 | public bool IsMatch(string input, int startat) Indica se l'espressione regolare specificata nel costruttore Regex trova una corrispondenza nella stringa di input specificata, a partire dalla posizione iniziale specificata nella stringa. |
3 | public static bool IsMatch(string input, string pattern) Indica se l'espressione regolare specificata trova una corrispondenza nella stringa di input specificata. |
4 | public MatchCollection Matches(string input) Cerca nella stringa di input specificata tutte le occorrenze di un'espressione regolare. |
5 | public string Replace(string input, string replacement) In una stringa di input specificata, sostituisce tutte le stringhe che corrispondono a un modello di espressione regolare con una stringa di sostituzione specificata. |
6 | public string[] Split(string input) Divide una stringa di input in una matrice di sottostringhe nelle posizioni definite da un modello di espressione regolare specificato nel costruttore Regex. |
Per l'elenco completo di metodi e proprietà, leggere la documentazione Microsoft su C #.
Esempio 1
L'esempio seguente trova parole che iniziano con "S" -
using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
class Program {
private static void showMatch(string text, string expr) {
Console.WriteLine("The Expression: " + expr);
MatchCollection mc = Regex.Matches(text, expr);
foreach (Match m in mc) {
Console.WriteLine(m);
}
}
static void Main(string[] args) {
string str = "A Thousand Splendid Suns";
Console.WriteLine("Matching words that start with 'S': ");
showMatch(str, @"\bS\S*");
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Matching words that start with 'S':
The Expression: \bS\S*
Splendid
Suns
Esempio 2
L'esempio seguente trova parole che iniziano con "m" e terminano con "e" -
using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
class Program {
private static void showMatch(string text, string expr) {
Console.WriteLine("The Expression: " + expr);
MatchCollection mc = Regex.Matches(text, expr);
foreach (Match m in mc) {
Console.WriteLine(m);
}
}
static void Main(string[] args) {
string str = "make maze and manage to measure it";
Console.WriteLine("Matching words start with 'm' and ends with 'e':");
showMatch(str, @"\bm\S*e\b");
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Matching words start with 'm' and ends with 'e':
The Expression: \bm\S*e\b
make
maze
manage
measure
Esempio 3
Questo esempio sostituisce lo spazio bianco aggiuntivo -
using System;
using System.Text.RegularExpressions;
namespace RegExApplication {
class Program {
static void Main(string[] args) {
string input = "Hello World ";
string pattern = "\\s+";
string replacement = " ";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(input, replacement);
Console.WriteLine("Original String: {0}", input);
Console.WriteLine("Replacement String: {0}", result);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Original String: Hello World
Replacement String: Hello World
Un'eccezione è un problema che sorge durante l'esecuzione di un programma. L'eccezione AC # è una risposta a una circostanza eccezionale che si verifica mentre un programma è in esecuzione, come un tentativo di divisione per zero.
Le eccezioni forniscono un modo per trasferire il controllo da una parte all'altra di un programma. La gestione delle eccezioni C # si basa su quattro parole chiave:try, catch, finally, e throw.
try- Un blocco try identifica un blocco di codice per il quale sono attivate particolari eccezioni. È seguito da uno o più blocchi di cattura.
catch- Un programma cattura un'eccezione con un gestore di eccezioni nel punto in cui si desidera gestire il problema. La parola chiave catch indica la cattura di un'eccezione.
finally- Il blocco finalmente viene utilizzato per eseguire un determinato insieme di istruzioni, indipendentemente dal fatto che venga generata un'eccezione o meno. Ad esempio, se apri un file, deve essere chiuso indipendentemente dal fatto che venga sollevata o meno un'eccezione.
throw- Un programma genera un'eccezione quando si presenta un problema. Questo viene fatto utilizzando una parola chiave throw.
Sintassi
Supponendo che un blocco sollevi un'eccezione, un metodo cattura un'eccezione utilizzando una combinazione delle parole chiave try and catch. Un blocco try / catch viene posizionato attorno al codice che potrebbe generare un'eccezione. Il codice all'interno di un blocco try / catch viene indicato come codice protetto e la sintassi per l'utilizzo di try / catch è la seguente:
try {
// statements causing exception
} catch( ExceptionName e1 ) {
// error handling code
} catch( ExceptionName e2 ) {
// error handling code
} catch( ExceptionName eN ) {
// error handling code
} finally {
// statements to be executed
}
Puoi elencare più istruzioni catch per rilevare diversi tipi di eccezioni nel caso in cui il tuo blocco try sollevi più di un'eccezione in situazioni diverse.
Classi di eccezione in C #
Le eccezioni C # sono rappresentate da classi. Le classi di eccezione in C # derivano principalmente direttamente o indirettamente daSystem.Exceptionclasse. Alcune delle classi di eccezione derivate dalla classe System.Exception sono leSystem.ApplicationException e System.SystemException classi.
Il System.ApplicationExceptionclass supporta le eccezioni generate dai programmi applicativi. Quindi le eccezioni definite dai programmatori dovrebbero derivare da questa classe.
Il System.SystemException class è la classe base per tutte le eccezioni di sistema predefinite.
La tabella seguente fornisce alcune delle classi di eccezioni predefinite derivate dalla classe Sytem.SystemException -
Sr.No. | Classe e descrizione dell'eccezione |
---|---|
1 | System.IO.IOException Gestisce gli errori di I / O. |
2 | System.IndexOutOfRangeException Gestisce gli errori generati quando un metodo fa riferimento a un indice di matrice fuori intervallo. |
3 | System.ArrayTypeMismatchException Gestisce gli errori generati quando il tipo non corrisponde al tipo di matrice. |
4 | System.NullReferenceException Gestisce gli errori generati dal riferimento a un oggetto nullo. |
5 | System.DivideByZeroException Gestisce gli errori generati dalla divisione di un dividendo per zero. |
6 | System.InvalidCastException Gestisce gli errori generati durante il typecasting. |
7 | System.OutOfMemoryException Gestisce gli errori generati da una memoria libera insufficiente. |
8 | System.StackOverflowException Gestisce gli errori generati dall'overflow dello stack. |
Gestione delle eccezioni
C # fornisce una soluzione strutturata alla gestione delle eccezioni sotto forma di blocchi try and catch. Utilizzando questi blocchi, le istruzioni del programma principale sono separate dalle istruzioni di gestione degli errori.
Questi blocchi di gestione degli errori vengono implementati utilizzando try, catch, e finallyparole chiave. Di seguito è riportato un esempio di generazione di un'eccezione quando si verifica la condizione di divisione per zero:
using System;
namespace ErrorHandlingApplication {
class DivNumbers {
int result;
DivNumbers() {
result = 0;
}
public void division(int num1, int num2) {
try {
result = num1 / num2;
} catch (DivideByZeroException e) {
Console.WriteLine("Exception caught: {0}", e);
} finally {
Console.WriteLine("Result: {0}", result);
}
}
static void Main(string[] args) {
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Exception caught: System.DivideByZeroException: Attempted to divide by zero.
at ...
Result: 0
Creazione di eccezioni definite dall'utente
Puoi anche definire la tua eccezione. Le classi di eccezioni definite dall'utente derivano daExceptionclasse. Il seguente esempio lo dimostra:
using System;
namespace UserDefinedException {
class TestTemperature {
static void Main(string[] args) {
Temperature temp = new Temperature();
try {
temp.showTemp();
} catch(TempIsZeroException e) {
Console.WriteLine("TempIsZeroException: {0}", e.Message);
}
Console.ReadKey();
}
}
}
public class TempIsZeroException: Exception {
public TempIsZeroException(string message): base(message) {
}
}
public class Temperature {
int temperature = 0;
public void showTemp() {
if(temperature == 0) {
throw (new TempIsZeroException("Zero Temperature found"));
} else {
Console.WriteLine("Temperature: {0}", temperature);
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
TempIsZeroException: Zero Temperature found
Lanciare oggetti
È possibile lanciare un oggetto se è direttamente o indirettamente derivato da System.Exceptionclasse. Puoi usare un'istruzione throw nel blocco catch per lanciare l'oggetto presente come:
Catch(Exception e) {
...
Throw e
}
UN fileè una raccolta di dati archiviati in un disco con un nome specifico e un percorso di directory. Quando un file viene aperto per la lettura o la scrittura, diventa un filestream.
Il flusso è fondamentalmente la sequenza di byte che passano attraverso il percorso di comunicazione. Ci sono due flussi principali: ilinput stream e il output stream. Il input stream viene utilizzato per leggere i dati dal file (operazione di lettura) e il file output stream viene utilizzato per scrivere nel file (operazione di scrittura).
Classi di I / O C #
Lo spazio dei nomi System.IO ha varie classi che vengono utilizzate per eseguire numerose operazioni con i file, come la creazione e l'eliminazione di file, la lettura o la scrittura su un file, la chiusura di un file ecc.
La tabella seguente mostra alcune classi non astratte di uso comune nello spazio dei nomi System.IO -
Sr.No. | Classe e descrizione I / O |
---|---|
1 | BinaryReader Legge i dati primitivi da un flusso binario. |
2 | BinaryWriter Scrive dati primitivi in formato binario. |
3 | BufferedStream Una memoria temporanea per un flusso di byte. |
4 | Directory Aiuta a manipolare una struttura di directory. |
5 | DirectoryInfo Utilizzato per eseguire operazioni sulle directory. |
6 | DriveInfo Fornisce informazioni per le unità. |
7 | File Aiuta a manipolare i file. |
8 | FileInfo Utilizzato per eseguire operazioni sui file. |
9 | FileStream Utilizzato per leggere e scrivere in qualsiasi posizione in un file. |
10 | MemoryStream Utilizzato per l'accesso casuale ai dati in streaming archiviati in memoria. |
11 | Path Esegue operazioni sulle informazioni sul percorso. |
12 | StreamReader Utilizzato per leggere caratteri da un flusso di byte. |
13 | StreamWriter Viene utilizzato per scrivere caratteri in un flusso. |
14 | StringReader Viene utilizzato per la lettura da un buffer di stringa. |
15 | StringWriter Viene utilizzato per scrivere in un buffer di stringhe. |
La classe FileStream
Il FileStreamclass nello spazio dei nomi System.IO aiuta a leggere, scrivere e chiudere file. Questa classe deriva dalla classe astratta Stream.
Devi creare un file FileStreamoggetto per creare un nuovo file o aprire un file esistente. La sintassi per creare un fileFileStream l'oggetto è il seguente -
FileStream <object_name> = new FileStream( <file_name>, <FileMode Enumerator>,
<FileAccess Enumerator>, <FileShare Enumerator>);
Ad esempio, creiamo un oggetto FileStream F per leggere un file denominato sample.txt as shown -
FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read,
FileShare.Read);
Sr.No. | Parametro e descrizione |
---|---|
1 | FileMode Il FileModeenumerator definisce vari metodi per aprire i file. I membri dell'enumeratore FileMode sono:
|
2 | FileAccess FileAccess gli enumeratori hanno membri: Read, ReadWrite e Write. |
3 | FileShare FileShare gli enumeratori hanno i seguenti membri:
|
Esempio
Il seguente programma mostra l'uso di FileStream classe -
using System;
using System.IO;
namespace FileIOApplication {
class Program {
static void Main(string[] args) {
FileStream F = new FileStream("test.dat", FileMode.OpenOrCreate,
FileAccess.ReadWrite);
for (int i = 1; i <= 20; i++) {
F.WriteByte((byte)i);
}
F.Position = 0;
for (int i = 0; i <= 20; i++) {
Console.Write(F.ReadByte() + " ");
}
F.Close();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -1
Operazioni avanzate sui file in C #
L'esempio precedente fornisce semplici operazioni sui file in C #. Tuttavia, per utilizzare gli immensi poteri delle classi System.IO C #, è necessario conoscere le proprietà ei metodi comunemente usati di queste classi.
Sr.No. | Argomento e descrizione |
---|---|
1 | Lettura da e scrittura in file di testo Implica la lettura e la scrittura in file di testo. IlStreamReader e StreamWriter la classe aiuta a realizzarlo. |
2 | Lettura da e scrittura in file binari Implica la lettura e la scrittura in file binari. IlBinaryReader e BinaryWriter la classe aiuta a raggiungere questo obiettivo. |
3 | Manipolazione del file system di Windows Fornisce a un programmatore C # la capacità di sfogliare e individuare file e directory di Windows. |
Un attributeè un tag dichiarativo che viene utilizzato per trasmettere informazioni al runtime sui comportamenti di vari elementi come classi, metodi, strutture, enumeratori, assembly ecc. nel programma. È possibile aggiungere informazioni dichiarative a un programma utilizzando un attributo. Un tag dichiarativo è rappresentato da parentesi quadre ([]) poste sopra l'elemento per cui è utilizzato.
Gli attributi vengono utilizzati per aggiungere metadati, come istruzioni del compilatore e altre informazioni come commenti, descrizione, metodi e classi a un programma. .Net Framework fornisce due tipi di attributi: gli attributi predefiniti e gli attributi personalizzati .
Specifica di un attributo
La sintassi per specificare un attributo è la seguente:
[attribute(positional_parameters, name_parameter = value, ...)]
element
Il nome dell'attributo e i suoi valori sono specificati all'interno delle parentesi quadre, prima dell'elemento a cui viene applicato l'attributo. I parametri posizionali specificano le informazioni essenziali ei parametri del nome specificano le informazioni facoltative.
Attributi predefiniti
.Net Framework fornisce tre attributi predefiniti:
- AttributeUsage
- Conditional
- Obsolete
AttributeUsage
L'attributo predefinito AttributeUsagedescrive come utilizzare una classe di attributi personalizzati. Specifica i tipi di elementi a cui può essere applicato l'attributo.
La sintassi per specificare questo attributo è la seguente:
[AttributeUsage (
validon,
AllowMultiple = allowmultiple,
Inherited = inherited
)]
Dove,
Il parametro validon specifica gli elementi del linguaggio su cui può essere posizionato l'attributo. È una combinazione del valore di un enumeratore AttributeTargets . Il valore predefinito è AttributeTargets.All .
Il parametro allowmultiple (facoltativo) fornisce un valore per la proprietà AllowMultiple di questo attributo, un valore booleano. Se questo è vero, l'attributo è multiuso. L'impostazione predefinita è false (monouso).
Il parametro inherited (facoltativo) fornisce un valore per la proprietà Inherited di questo attributo, un valore booleano. Se è vero, l'attributo viene ereditato dalle classi derivate. Il valore predefinito è false (non ereditato).
Per esempio,
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
Condizionale
Questo attributo predefinito contrassegna un metodo condizionale la cui esecuzione dipende da un identificatore di pre-elaborazione specificato.
Provoca la compilazione condizionale delle chiamate al metodo, a seconda del valore specificato come Debug o Trace. Ad esempio, visualizza i valori delle variabili durante il debug di un codice.
La sintassi per specificare questo attributo è la seguente:
[Conditional(
conditionalSymbol
)]
Per esempio,
[Conditional("DEBUG")]
Il seguente esempio dimostra l'attributo -
#define DEBUG
using System;
using System.Diagnostics;
public class Myclass {
[Conditional("DEBUG")]
public static void Message(string msg) {
Console.WriteLine(msg);
}
}
class Test {
static void function1() {
Myclass.Message("In Function 1.");
function2();
}
static void function2() {
Myclass.Message("In Function 2.");
}
public static void Main() {
Myclass.Message("In Main function.");
function1();
Console.ReadKey();
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
In Main function
In Function 1
In Function 2
Obsoleto
Questo attributo predefinito contrassegna un'entità del programma che non deve essere utilizzata. Consente di informare il compilatore di scartare un particolare elemento di destinazione. Ad esempio, quando un nuovo metodo viene utilizzato in una classe e se si desidera ancora conservare il vecchio metodo nella classe, è possibile contrassegnarlo come obsoleto visualizzando un messaggio, il nuovo metodo dovrebbe essere utilizzato, invece del vecchio metodo.
La sintassi per specificare questo attributo è la seguente:
[Obsolete (
message
)]
[Obsolete (
message,
iserror
)]
Dove,
Il messaggio del parametro , è una stringa che descrive il motivo per cui l'elemento è obsoleto e cosa usare invece.
Il parametro iserror , è un valore booleano. Se il suo valore è vero, il compilatore dovrebbe considerare l'uso dell'elemento come un errore. Il valore predefinito è false (il compilatore genera un avviso).
Il seguente programma lo dimostra:
using System;
public class MyClass {
[Obsolete("Don't use OldMethod, use NewMethod instead", true)]
static void OldMethod() {
Console.WriteLine("It is the old method");
}
static void NewMethod() {
Console.WriteLine("It is the new method");
}
public static void Main() {
OldMethod();
}
}
Quando si tenta di compilare il programma, il compilatore fornisce un messaggio di errore che indica:
Don't use OldMethod, use NewMethod instead
Creazione di attributi personalizzati
.Net Framework consente la creazione di attributi personalizzati che possono essere utilizzati per memorizzare informazioni dichiarative e possono essere recuperati in fase di esecuzione. Queste informazioni possono essere correlate a qualsiasi elemento target a seconda dei criteri di progettazione e delle esigenze dell'applicazione.
La creazione e l'utilizzo di attributi personalizzati comportano quattro passaggi:
- Dichiarazione di un attributo personalizzato
- Costruire l'attributo personalizzato
- Applicare l'attributo personalizzato a un elemento del programma di destinazione
- Accesso agli attributi tramite la riflessione
L'ultimo passaggio prevede la scrittura di un semplice programma per leggere i metadati per trovare varie notazioni. I metadati sono dati su dati o informazioni utilizzati per descrivere altri dati. Questo programma dovrebbe utilizzare le riflessioni per accedere agli attributi in fase di esecuzione. Di questo discuteremo nel prossimo capitolo.
Dichiarazione di un attributo personalizzato
Un nuovo attributo personalizzato dovrebbe derivare da System.Attributeclasse. Per esempio,
//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
Nel codice precedente, abbiamo dichiarato un attributo personalizzato denominato DeBugInfo .
Costruire l'attributo personalizzato
Costruiamo un attributo personalizzato denominato DeBugInfo , che memorizza le informazioni ottenute eseguendo il debug di qualsiasi programma. Lascia che memorizzi le seguenti informazioni:
- Il numero di codice del bug
- Nome dello sviluppatore che ha identificato il bug
- Data dell'ultima revisione del codice
- Un messaggio di stringa per memorizzare i commenti dello sviluppatore
La classe DeBugInfo ha tre proprietà private per archiviare le prime tre informazioni e una proprietà pubblica per archiviare il messaggio. Quindi il numero di bug, il nome dello sviluppatore e la data di revisione sono i parametri posizionali della classe DeBugInfo e il messaggio è un parametro facoltativo o denominato.
Ogni attributo deve avere almeno un costruttore. I parametri posizionali dovrebbero essere passati attraverso il costruttore. Il codice seguente mostra la classe DeBugInfo -
//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute {
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d) {
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo {
get {
return bugNo;
}
}
public string Developer {
get {
return developer;
}
}
public string LastReview {
get {
return lastReview;
}
}
public string Message {
get {
return message;
}
set {
message = value;
}
}
}
Applicazione dell'attributo personalizzato
L'attributo viene applicato posizionandolo immediatamente prima del suo obiettivo -
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle {
//member variables
protected double length;
protected double width;
public Rectangle(double l, double w) {
length = l;
width = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
public double GetArea() {
return length * width;
}
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}
Nel prossimo capitolo, recupereremo le informazioni sugli attributi utilizzando un oggetto della classe Reflection.
Reflectiongli oggetti vengono utilizzati per ottenere informazioni sul tipo in fase di esecuzione. Le classi che danno accesso ai metadati di un programma in esecuzione si trovano inSystem.Reflection spazio dei nomi.
Il System.Reflection namespace contiene classi che consentono di ottenere informazioni sull'applicazione e di aggiungere dinamicamente tipi, valori e oggetti all'applicazione.
Applicazioni della riflessione
Reflection ha le seguenti applicazioni:
Consente di visualizzare le informazioni sugli attributi in fase di esecuzione.
Consente di esaminare vari tipi in un assembly e di istanziare questi tipi.
Consente l'associazione tardiva a metodi e proprietà
Consente di creare nuovi tipi in fase di esecuzione e quindi esegue alcune attività utilizzando tali tipi.
Visualizzazione dei metadati
Abbiamo accennato nel capitolo precedente che usando la riflessione è possibile visualizzare le informazioni sugli attributi.
Il MemberInfo oggetto del System.Reflectionclass deve essere inizializzato per scoprire gli attributi associati a una classe. Per fare ciò, definisci un oggetto della classe di destinazione, come:
System.Reflection.MemberInfo info = typeof(MyClass);
Il seguente programma lo dimostra:
using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
public readonly string Url;
public string Topic // Topic is a named parameter {
get {
return topic;
}
set {
topic = value;
}
}
public HelpAttribute(string url) // url is a positional parameter {
this.Url = url;
}
private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass {
}
namespace AttributeAppl {
class Program {
static void Main(string[] args) {
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++) {
System.Console.WriteLine(attributes[i]);
}
Console.ReadKey();
}
}
}
Quando viene compilato ed eseguito, visualizza il nome degli attributi personalizzati allegati alla classe MyClass -
HelpAttribute
Esempio
In questo esempio, usiamo l' attributo DeBugInfo creato nel capitolo precedente e usiamo la riflessione per leggere i metadati nella classe Rectangle .
using System;
using System.Reflection;
namespace BugFixApplication {
//a custom attribute BugFix to be
//assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute {
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d) {
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo {
get {
return bugNo;
}
}
public string Developer {
get {
return developer;
}
}
public string LastReview {
get {
return lastReview;
}
}
public string Message {
get {
return message;
}
set {
message = value;
}
}
}
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle {
//member variables
protected double length;
protected double width;
public Rectangle(double l, double w) {
length = l;
width = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
public double GetArea() {
return length * width;
}
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Display() {
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}//end class Rectangle
class ExecuteRectangle {
static void Main(string[] args) {
Rectangle r = new Rectangle(4.5, 7.5);
r.Display();
Type type = typeof(Rectangle);
//iterating through the attribtues of the Rectangle class
foreach (Object attributes in type.GetCustomAttributes(false)) {
DeBugInfo dbi = (DeBugInfo)attributes;
if (null != dbi) {
Console.WriteLine("Bug no: {0}", dbi.BugNo);
Console.WriteLine("Developer: {0}", dbi.Developer);
Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
Console.WriteLine("Remarks: {0}", dbi.Message);
}
}
//iterating through the method attribtues
foreach (MethodInfo m in type.GetMethods()) {
foreach (Attribute a in m.GetCustomAttributes(true)) {
DeBugInfo dbi = (DeBugInfo)a;
if (null != dbi) {
Console.WriteLine("Bug no: {0}, for Method: {1}", dbi.BugNo, m.Name);
Console.WriteLine("Developer: {0}", dbi.Developer);
Console.WriteLine("Last Reviewed: {0}", dbi.LastReview);
Console.WriteLine("Remarks: {0}", dbi.Message);
}
}
}
Console.ReadLine();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks:
Propertiessono denominati membri di classi, strutture e interfacce. Vengono chiamati variabili membro o metodi in una classe o struttureFields. Le proprietà sono un'estensione dei campi e sono accessibili utilizzando la stessa sintassi. Usanoaccessors attraverso il quale i valori dei campi privati possono essere letti, scritti o manipolati.
Le proprietà non denominano le posizioni di archiviazione. Invece, l'hanno fattoaccessors che leggono, scrivono o calcolano i loro valori.
Ad esempio, disponiamo di una classe denominata Studente, con campi privati per età, nome e codice. Non possiamo accedere direttamente a questi campi dall'esterno dell'ambito della classe, ma possiamo avere proprietà per accedere a questi campi privati.
Accessors
Il accessordi una proprietà contiene le istruzioni eseguibili che aiutano a ottenere (leggere o elaborare) o impostare (scrivere) la proprietà. Le dichiarazioni della funzione di accesso possono contenere una funzione di accesso get, una funzione di accesso set o entrambe. Ad esempio:
// Declare a Code property of type string:
public string Code {
get {
return code;
}
set {
code = value;
}
}
// Declare a Name property of type string:
public string Name {
get {
return name;
}
set {
name = value;
}
}
// Declare a Age property of type int:
public int Age {
get {
return age;
}
set {
age = value;
}
}
Esempio
Il seguente esempio dimostra l'uso delle proprietà:
using System;
namespace tutorialspoint {
class Student {
private string code = "N.A";
private string name = "not known";
private int age = 0;
// Declare a Code property of type string:
public string Code {
get {
return code;
}
set {
code = value;
}
}
// Declare a Name property of type string:
public string Name {
get {
return name;
}
set {
name = value;
}
}
// Declare a Age property of type int:
public int Age {
get {
return age;
}
set {
age = value;
}
}
public override string ToString() {
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo {
public static void Main() {
// Create a new Student object:
Student s = new Student();
// Setting code, name and the age of the student
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info: {0}", s);
//let us increase age
s.Age += 1;
Console.WriteLine("Student Info: {0}", s);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10
Proprietà astratte
Una classe astratta può avere una proprietà astratta, che dovrebbe essere implementata nella classe derivata. Il seguente programma lo illustra:
using System;
namespace tutorialspoint {
public abstract class Person {
public abstract string Name {
get;
set;
}
public abstract int Age {
get;
set;
}
}
class Student : Person {
private string code = "N.A";
private string name = "N.A";
private int age = 0;
// Declare a Code property of type string:
public string Code {
get {
return code;
}
set {
code = value;
}
}
// Declare a Name property of type string:
public override string Name {
get {
return name;
}
set {
name = value;
}
}
// Declare a Age property of type int:
public override int Age {
get {
return age;
}
set {
age = value;
}
}
public override string ToString() {
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo {
public static void Main() {
// Create a new Student object:
Student s = new Student();
// Setting code, name and the age of the student
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info:- {0}", s);
//let us increase age
s.Age += 1;
Console.WriteLine("Student Info:- {0}", s);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Student Info: Code = 001, Name = Zara, Age = 9
Student Info: Code = 001, Name = Zara, Age = 10
Un indexerconsente a un oggetto di essere indicizzato come un array. Quando si definisce un indicizzatore per una classe, questa si comporta in modo simile a un filevirtual array. È quindi possibile accedere all'istanza di questa classe utilizzando l'operatore di accesso all'array ([]).
Sintassi
Un indicizzatore unidimensionale ha la seguente sintassi:
element-type this[int index] {
// The get accessor.
get {
// return the value specified by index
}
// The set accessor.
set {
// set the value specified by index
}
}
Uso di indicizzatori
La dichiarazione di comportamento di un indicizzatore è in una certa misura simile a una proprietà. simile alle proprietà che usi get e setfunzioni di accesso per la definizione di un indicizzatore. Tuttavia, le proprietà restituiscono o impostano un membro dati specifico, mentre gli indicizzatori restituiscono o impostano un valore particolare dall'istanza dell'oggetto. In altre parole, suddivide i dati dell'istanza in parti più piccole e indicizza ogni parte, ottiene o imposta ogni parte.
La definizione di una proprietà implica fornire un nome di proprietà. Gli indicizzatori non vengono definiti con nomi, ma conthisparola chiave, che fa riferimento all'istanza dell'oggetto. Il seguente esempio dimostra il concetto:
using System;
namespace IndexerApplication {
class IndexedNames {
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames() {
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index] {
get {
string tmp;
if( index >= 0 && index <= size-1 ) {
tmp = namelist[index];
} else {
tmp = "";
}
return ( tmp );
}
set {
if( index >= 0 && index <= size-1 ) {
namelist[index] = value;
}
}
}
static void Main(string[] args) {
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
for ( int i = 0; i < IndexedNames.size; i++ ) {
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
Indicizzatori sovraccarichi
Gli indicizzatori possono essere sovraccaricati. Gli indicizzatori possono anche essere dichiarati con più parametri e ogni parametro può essere di un tipo diverso. Non è necessario che gli indici debbano essere numeri interi. C # consente agli indici di essere di altri tipi, ad esempio una stringa.
L'esempio seguente mostra gli indicizzatori sovraccaricati:
using System;
namespace IndexerApplication {
class IndexedNames {
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames() {
for (int i = 0; i < size; i++) {
namelist[i] = "N. A.";
}
}
public string this[int index] {
get {
string tmp;
if( index >= 0 && index <= size-1 ) {
tmp = namelist[index];
} else {
tmp = "";
}
return ( tmp );
}
set {
if( index >= 0 && index <= size-1 ) {
namelist[index] = value;
}
}
}
public int this[string name] {
get {
int index = 0;
while(index < size) {
if (namelist[index] == name) {
return index;
}
index++;
}
return index;
}
}
static void Main(string[] args) {
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
//using the first indexer with int parameter
for (int i = 0; i < IndexedNames.size; i++) {
Console.WriteLine(names[i]);
}
//using the second indexer with the string parameter
Console.WriteLine(names["Nuha"]);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
2
I delegati C # sono simili ai puntatori alle funzioni, in C o C ++. UNdelegateè una variabile del tipo di riferimento che contiene il riferimento a un metodo. Il riferimento può essere modificato in fase di esecuzione.
I delegati sono usati specialmente per implementare eventi e metodi di callback. Tutti i delegati derivano implicitamente daSystem.Delegate classe.
Dichiarazione dei delegati
La dichiarazione del delegato determina i metodi a cui può fare riferimento il delegato. Un delegato può fare riferimento a un metodo, che ha la stessa firma di quella del delegato.
Ad esempio, considera un delegato:
public delegate int MyDelegate (string s);
Il delegato precedente può essere usato per fare riferimento a qualsiasi metodo che abbia un singolo parametro di stringa e restituisca una variabile di tipo int .
La sintassi per la dichiarazione del delegato è:
delegate <return type> <delegate-name> <parameter list>
Creazione di istanze dei delegati
Dopo aver dichiarato un tipo di delegato, è necessario creare un oggetto delegato con l'estensione new parola chiave ed essere associato a un metodo particolare. Durante la creazione di un delegato, l'argomento è passato anewl'espressione viene scritta in modo simile a una chiamata a un metodo, ma senza gli argomenti del metodo. Ad esempio:
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
L'esempio seguente dimostra la dichiarazione, la creazione di istanze e l'uso di un delegato che può essere usato per fare riferimento a metodi che accettano un parametro intero e restituisce un valore intero.
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
//create delegate instances
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
//calling the methods using the delegate objects
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Value of Num: 35
Value of Num: 175
Multicasting di un delegato
Gli oggetti delegato possono essere composti utilizzando l'operatore "+". Un delegato composto chiama i due delegati da cui è stato composto. È possibile comporre solo delegati dello stesso tipo. L'operatore "-" può essere utilizzato per rimuovere un delegato componente da un delegato composto.
Utilizzando questa proprietà dei delegati è possibile creare un elenco di chiamate di metodi che verranno chiamati quando viene richiamato un delegato. Questo è chiamatomulticastingdi un delegato. Il seguente programma dimostra il multicasting di un delegato:
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
//create delegate instances
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
//calling multicast
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Value of Num: 75
Utilizzo dei delegati
L'esempio seguente mostra l'uso di delegate. Il delegato printString può essere utilizzato per fare riferimento a un metodo che accetta una stringa come input e non restituisce nulla.
Usiamo questo delegato per chiamare due metodi, il primo stampa la stringa sulla console e il secondo la stampa su un file -
using System;
using System.IO;
namespace DelegateAppl {
class PrintString {
static FileStream fs;
static StreamWriter sw;
// delegate declaration
public delegate void printString(string s);
// this method prints to the console
public static void WriteToScreen(string str) {
Console.WriteLine("The String is: {0}", str);
}
//this method prints to a file
public static void WriteToFile(string s) {
fs = new FileStream("c:\\message.txt",
FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
sw.WriteLine(s);
sw.Flush();
sw.Close();
fs.Close();
}
// this method takes the delegate as parameter and uses it to
// call the methods as required
public static void sendString(printString ps) {
ps("Hello World");
}
static void Main(string[] args) {
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
sendString(ps1);
sendString(ps2);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
The String is: Hello World
Eventssono azioni dell'utente come pressione di tasti, clic, movimenti del mouse, ecc. o alcune occorrenze come notifiche generate dal sistema. Le applicazioni devono rispondere agli eventi quando si verificano. Ad esempio, interrompe. Gli eventi vengono utilizzati per la comunicazione tra processi.
Utilizzo di delegati con eventi
Gli eventi vengono dichiarati e generati in una classe e associati ai gestori di eventi utilizzando delegati all'interno della stessa classe o di un'altra classe. La classe contenente l'evento viene utilizzata per pubblicare l'evento. Questo è chiamatopublisherclasse. Un'altra classe che accetta questo evento è chiamatasubscriber classe. Gli eventi utilizzano l'estensionepublisher-subscriber modello.
UN publisherè un oggetto che contiene la definizione dell'evento e del delegato. Anche l'associazione del delegato dell'evento è definita in questo oggetto. Un oggetto della classe editore richiama l'evento e viene notificato ad altri oggetti.
UN subscriberè un oggetto che accetta l'evento e fornisce un gestore di eventi. Il delegato nella classe editore richiama il metodo (gestore eventi) della classe del sottoscrittore.
Dichiarazione di eventi
Per dichiarare un evento all'interno di una classe, prima di tutto, devi dichiarare un tipo delegato per il pari come:
public delegate string BoilerLogHandler(string str);
quindi, dichiara l'evento utilizzando il event parola chiave -
event BoilerLogHandler BoilerEventLog;
Il codice precedente definisce un delegato denominato BoilerLogHandler e un evento denominato BoilerEventLog , che richiama il delegato quando viene generato.
Esempio
using System;
namespace SampleApp {
public delegate string MyDel(string str);
class EventProgram {
event MyDel MyEvent;
public EventProgram() {
this.MyEvent += new MyDel(this.WelcomeUser);
}
public string WelcomeUser(string username) {
return "Welcome " + username;
}
static void Main(string[] args) {
EventProgram obj1 = new EventProgram();
string result = obj1.MyEvent("Tutorials Point");
Console.WriteLine(result);
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Welcome Tutorials Point
Le classi di raccolta sono classi specializzate per l'archiviazione e il recupero dei dati. Queste classi forniscono supporto per stack, code, elenchi e tabelle hash. La maggior parte delle classi di raccolta implementa le stesse interfacce.
Le classi di raccolta servono a vari scopi, come l'allocazione dinamica della memoria agli elementi e l'accesso a un elenco di elementi sulla base di un indice, ecc. Queste classi creano raccolte di oggetti della classe Object, che è la classe base per tutti i tipi di dati in C #.
Varie classi di raccolte e loro utilizzo
Le seguenti sono le varie classi comunemente usate di System.Collectionspazio dei nomi. Fare clic sui seguenti collegamenti per verificarne i dettagli.
Sr.No. | Classe, descrizione e utilizzo |
---|---|
1 | Lista di array Rappresenta la raccolta ordinata di un oggetto che può essere indexed individualmente. È fondamentalmente un'alternativa a un array. Tuttavia, a differenza dell'array, puoi aggiungere e rimuovere elementi da un elenco in una posizione specificata utilizzando un fileindexe l'array si ridimensiona automaticamente. Consente inoltre l'allocazione dinamica della memoria, l'aggiunta, la ricerca e l'ordinamento degli elementi nell'elenco. |
2 | Hashtable Utilizza un file key per accedere agli elementi della collezione. Una tabella hash viene utilizzata quando è necessario accedere agli elementi utilizzando la chiave ed è possibile identificare un valore chiave utile. Ogni elemento nella tabella hash ha un'estensionekey/valuepaio. La chiave viene utilizzata per accedere agli elementi della collezione. |
3 | SortedList Utilizza un file key così come un index per accedere agli elementi in un elenco. Un elenco ordinato è una combinazione di un array e una tabella hash. Contiene un elenco di elementi a cui è possibile accedere utilizzando una chiave o un indice. Se accedi agli elementi utilizzando un indice, si tratta di un ArrayList e se accedi agli elementi utilizzando una chiave, è un Hashtable. La raccolta di elementi viene sempre ordinata in base al valore della chiave. |
4 | Pila Rappresenta un last-in, first out raccolta di oggetti. Viene utilizzato quando è necessario un accesso per ultimo agli elementi. Quando aggiungi un elemento nell'elenco, viene chiamatopushing l'elemento e quando lo rimuovi, viene chiamato popping l'oggetto. |
5 | Coda Rappresenta un first-in, first out raccolta di oggetti. Viene utilizzato quando è necessario un accesso first-in, first-out degli elementi. Quando aggiungi un elemento nell'elenco, viene chiamatoenqueue e quando rimuovi un elemento, viene chiamato deque. |
6 | BitArray Rappresenta un array di binary representation utilizzando i valori 1 e 0. Viene utilizzato quando è necessario memorizzare i bit ma non si conosce in anticipo il numero di bit. È possibile accedere agli elementi dalla raccolta BitArray utilizzando un fileinteger index, che parte da zero. |
Genericsconsentono di definire la specifica del tipo di dati degli elementi di programmazione in una classe o in un metodo, fino a quando non viene effettivamente utilizzato nel programma. In altre parole, i generici ti consentono di scrivere una classe o un metodo che può funzionare con qualsiasi tipo di dati.
Si scrivono le specifiche per la classe o il metodo, con parametri sostitutivi per i tipi di dati. Quando il compilatore incontra un costruttore per la classe o una chiamata di funzione per il metodo, genera codice per gestire il tipo di dati specifico. Un semplice esempio aiuterebbe a comprendere il concetto:
using System;
using System.Collections.Generic;
namespace GenericApplication {
public class MyGenericArray<T> {
private T[] array;
public MyGenericArray(int size) {
array = new T[size + 1];
}
public T getItem(int index) {
return array[index];
}
public void setItem(int index, T value) {
array[index] = value;
}
}
class Tester {
static void Main(string[] args) {
//declaring an int array
MyGenericArray<int> intArray = new MyGenericArray<int>(5);
//setting values
for (int c = 0; c < 5; c++) {
intArray.setItem(c, c*5);
}
//retrieving the values
for (int c = 0; c < 5; c++) {
Console.Write(intArray.getItem(c) + " ");
}
Console.WriteLine();
//declaring a character array
MyGenericArray<char> charArray = new MyGenericArray<char>(5);
//setting values
for (int c = 0; c < 5; c++) {
charArray.setItem(c, (char)(c+97));
}
//retrieving the values
for (int c = 0; c< 5; c++) {
Console.Write(charArray.getItem(c) + " ");
}
Console.WriteLine();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
0 5 10 15 20
a b c d e
Caratteristiche dei generici
I generici sono una tecnica che arricchisce i tuoi programmi nei seguenti modi:
Ti aiuta a massimizzare il riutilizzo del codice, l'indipendenza dai tipi e le prestazioni.
È possibile creare classi di raccolte generiche. La libreria di classi .NET Framework contiene diverse nuove classi di raccolte generiche nello spazio dei nomi System.Collections.Generic . È possibile utilizzare queste classi di raccolta generiche invece delle classi di raccolta nello spazio dei nomi System.Collections .
È possibile creare interfacce, classi, metodi, eventi e delegati generici personalizzati.
È possibile creare classi generiche vincolate per consentire l'accesso a metodi su particolari tipi di dati.
È possibile ottenere informazioni sui tipi utilizzati in un tipo di dati generico in fase di esecuzione mediante la riflessione.
Metodi generici
Nell'esempio precedente, abbiamo utilizzato una classe generica; possiamo dichiarare un metodo generico con un parametro di tipo. Il seguente programma illustra il concetto:
using System;
using System.Collections.Generic;
namespace GenericMethodAppl {
class Program {
static void Swap<T>(ref T lhs, ref T rhs) {
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args) {
int a, b;
char c, d;
a = 10;
b = 20;
c = 'I';
d = 'V';
//display values before swap:
Console.WriteLine("Int values before calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values before calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
//call swap
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
//display values after swap:
Console.WriteLine("Int values after calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values after calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I
Delegati generici
È possibile definire un delegato generico con parametri di tipo. Ad esempio:
delegate T NumberChanger<T>(T n);
L'esempio seguente mostra l'uso di questo delegato:
using System;
using System.Collections.Generic;
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
//create delegate instances
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
//calling the methods using the delegate objects
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Value of Num: 35
Value of Num: 175
Abbiamo discusso che i delegati vengono usati per fare riferimento a qualsiasi metodo che abbia la stessa firma di quella del delegato. In altre parole, è possibile chiamare un metodo a cui può fare riferimento un delegato utilizzando quell'oggetto delegato.
Anonymous methodsfornire una tecnica per passare un blocco di codice come parametro delegato. I metodi anonimi sono i metodi senza nome, solo il corpo.
Non è necessario specificare il tipo di ritorno in un metodo anonimo; viene dedotto dall'istruzione return all'interno del corpo del metodo.
Scrivere un metodo anonimo
I metodi anonimi vengono dichiarati con la creazione dell'istanza del delegato, con un file delegateparola chiave. Per esempio,
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x) {
Console.WriteLine("Anonymous Method: {0}", x);
};
Il blocco di codice Console.WriteLine ("Metodo anonimo: {0}", x); è il corpo del metodo anonimo.
Il delegato può essere chiamato sia con metodi anonimi che con metodi denominati nello stesso modo, ovvero passando i parametri del metodo all'oggetto delegato.
Per esempio,
nc(10);
Esempio
Il seguente esempio dimostra il concetto:
using System;
delegate void NumberChanger(int n);
namespace DelegateAppl {
class TestDelegate {
static int num = 10;
public static void AddNum(int p) {
num += p;
Console.WriteLine("Named Method: {0}", num);
}
public static void MultNum(int q) {
num *= q;
Console.WriteLine("Named Method: {0}", num);
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
//create delegate instances using anonymous method
NumberChanger nc = delegate(int x) {
Console.WriteLine("Anonymous Method: {0}", x);
};
//calling the delegate using the anonymous method
nc(10);
//instantiating the delegate using the named methods
nc = new NumberChanger(AddNum);
//calling the delegate using the named methods
nc(5);
//instantiating the delegate using another named methods
nc = new NumberChanger(MultNum);
//calling the delegate using the named methods
nc(2);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Anonymous Method: 10
Named Method: 15
Named Method: 30
C # consente di utilizzare le variabili del puntatore in una funzione del blocco di codice quando è contrassegnata dal unsafemodificatore. Ilunsafe code oppure il codice non gestito è un blocco di codice che utilizza un file pointer variabile.
Note- Per eseguire i programmi menzionati in questo capitolo su codingground , impostare l'opzione di compilazione in Progetto >> Opzioni di compilazione >> Comando di compilazione su
mcs *.cs -out:main.exe -unsafe"
Puntatori
UN pointerè una variabile il cui valore è l'indirizzo di un'altra variabile, cioè l'indirizzo diretto della posizione di memoria. simile a qualsiasi variabile o costante, è necessario dichiarare un puntatore prima di poterlo utilizzare per memorizzare qualsiasi indirizzo di variabile.
La forma generale di una dichiarazione di puntatore è:
type *var-name;
Di seguito sono riportate dichiarazioni di puntatore valide:
int *ip; /* pointer to an integer */
double *dp; /* pointer to a double */
float *fp; /* pointer to a float */
char *ch /* pointer to a character */
L'esempio seguente illustra l'uso dei puntatori in C #, usando il modificatore unsafe -
using System;
namespace UnsafeCodeApplication {
class Program {
static unsafe void Main(string[] args) {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Address is: {0}", (int)p);
Console.ReadKey();
}
}
}
Quando il codice precedente è stato compilato ed eseguito, produce il seguente risultato:
Data is: 20
Address is: 99215364
Invece di dichiarare un intero metodo come non sicuro, puoi anche dichiarare una parte del codice come non sicura. L'esempio nella sezione seguente lo mostra.
Recupero del valore dei dati utilizzando un puntatore
È possibile recuperare i dati memorizzati nella posizione a cui fa riferimento la variabile pointer, utilizzando il ToString()metodo. Il seguente esempio lo dimostra:
using System;
namespace UnsafeCodeApplication {
class Program {
public static void Main() {
unsafe {
int var = 20;
int* p = &var;
Console.WriteLine("Data is: {0} " , var);
Console.WriteLine("Data is: {0} " , p->ToString());
Console.WriteLine("Address is: {0} " , (int)p);
}
Console.ReadKey();
}
}
}
Quando il codice precedente è stato compilato ed eseguito, produce il seguente risultato:
Data is: 20
Data is: 20
Address is: 77128984
Passaggio di puntatori come parametri ai metodi
È possibile passare una variabile puntatore a un metodo come parametro. Il seguente esempio lo illustra:
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe void swap(int* p, int *q) {
int temp = *p;
*p = *q;
*q = temp;
}
public unsafe static void Main() {
TestPointer p = new TestPointer();
int var1 = 10;
int var2 = 20;
int* x = &var1;
int* y = &var2;
Console.WriteLine("Before Swap: var1:{0}, var2: {1}", var1, var2);
p.swap(x, y);
Console.WriteLine("After Swap: var1:{0}, var2: {1}", var1, var2);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
Before Swap: var1: 10, var2: 20
After Swap: var1: 20, var2: 10
Accesso agli elementi della matrice utilizzando un puntatore
In C #, un nome di matrice e un puntatore a un tipo di dati uguale ai dati di matrice non sono lo stesso tipo di variabile. Ad esempio, int * p e int [] p non sono dello stesso tipo. È possibile incrementare la variabile puntatore p perché non è fissata in memoria ma un indirizzo di matrice è fisso in memoria e non è possibile incrementarlo.
Pertanto, se è necessario accedere ai dati di un array utilizzando una variabile del puntatore, come si fa tradizionalmente in C o C ++ (controllare: Puntatori C ), è necessario correggere il puntatore utilizzando ilfixed parola chiave.
Il seguente esempio lo dimostra:
using System;
namespace UnsafeCodeApplication {
class TestPointer {
public unsafe static void Main() {
int[] list = {10, 100, 200};
fixed(int *ptr = list)
/* let us have array address in pointer */
for ( int i = 0; i < 3; i++) {
Console.WriteLine("Address of list[{0}]={1}",i,(int)(ptr + i));
Console.WriteLine("Value of list[{0}]={1}", i, *(ptr + i));
}
Console.ReadKey();
}
}
}
Quando il codice precedente è stato compilato ed eseguito, produce il seguente risultato:
Address of list[0] = 31627168
Value of list[0] = 10
Address of list[1] = 31627172
Value of list[1] = 100
Address of list[2] = 31627176
Value of list[2] = 200
Compilazione di codice non sicuro
Per compilare codice non sicuro, è necessario specificare il file /unsafe switch della riga di comando con compilatore della riga di comando.
Ad esempio, per compilare un programma denominato prog1.cs contenente codice non sicuro, dalla riga di comando, dare il comando -
csc /unsafe prog1.cs
Se stai usando l'IDE di Visual Studio, devi abilitare l'uso di codice non sicuro nelle proprietà del progetto.
Per fare questo -
Aperto project properties facendo doppio clic sul nodo delle proprietà in Esplora soluzioni.
Clicca sul Build tab.
Seleziona l'opzione "Allow unsafe code".
UN threadè definito come il percorso di esecuzione di un programma. Ogni thread definisce un flusso di controllo univoco. Se l'applicazione prevede operazioni complicate e dispendiose in termini di tempo, è spesso utile impostare percorsi o thread di esecuzione diversi, con ogni thread che esegue un lavoro particolare.
I thread sono lightweight processes. Un esempio comune di utilizzo del thread è l'implementazione della programmazione concorrente da parte dei sistemi operativi moderni. L'utilizzo di thread consente di risparmiare spreco di ciclo della CPU e aumentare l'efficienza di un'applicazione.
Finora abbiamo scritto i programmi in cui un singolo thread viene eseguito come un singolo processo che è l'istanza in esecuzione dell'applicazione. Tuttavia, in questo modo l'applicazione può eseguire un lavoro alla volta. Per farlo eseguire più di un'attività alla volta, potrebbe essere diviso in thread più piccoli.
Ciclo di vita del filo
Il ciclo di vita di un thread inizia quando viene creato un oggetto della classe System.Threading.Thread e termina quando il thread viene terminato o completa l'esecuzione.
Di seguito sono riportati i vari stati nel ciclo di vita di un thread:
The Unstarted State - È la situazione in cui viene creata l'istanza del thread ma il metodo Start non viene chiamato.
The Ready State - È la situazione in cui il thread è pronto per essere eseguito e in attesa del ciclo della CPU.
The Not Runnable State - Un thread non è eseguibile, quando
- È stato chiamato il metodo del sonno
- Il metodo Wait è stato chiamato
- Bloccato dalle operazioni di I / O
The Dead State - È la situazione in cui il thread completa l'esecuzione o viene interrotto.
Il filo conduttore
In C #, il System.Threading.Threadclass viene utilizzata per lavorare con i thread. Consente la creazione e l'accesso a singoli thread in un'applicazione multithread. Il primo thread da eseguire in un processo è chiamatomain filo.
Quando un programma C # inizia l'esecuzione, il thread principale viene creato automaticamente. I thread creati utilizzando ilThreadsono chiamati thread secondari del thread principale. È possibile accedere a un thread utilizzando ilCurrentThread proprietà della classe Thread.
Il seguente programma mostra l'esecuzione del thread principale:
using System;
using System.Threading;
namespace MultithreadingApplication {
class MainThreadProgram {
static void Main(string[] args) {
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
This is MainThread
Proprietà e metodi della classe Thread
La tabella seguente mostra alcuni dei più comunemente usati properties del Thread classe -
Sr.No. | Proprietà e descrizione |
---|---|
1 | CurrentContext Ottiene il contesto corrente in cui è in esecuzione il thread. |
2 | CurrentCulture Ottiene o imposta le impostazioni cultura per il thread corrente. |
3 | CurrentPrinciple Ottiene o imposta l'entità corrente del thread (per la sicurezza basata sui ruoli). |
4 | CurrentThread Ottiene il thread attualmente in esecuzione. |
5 | CurrentUICulture Ottiene o imposta le impostazioni cultura correnti usate da Resource Manager per cercare risorse specifiche delle impostazioni cultura in fase di esecuzione. |
6 | ExecutionContext Ottiene un oggetto ExecutionContext che contiene informazioni sui vari contesti del thread corrente. |
7 | IsAlive Ottiene un valore che indica lo stato di esecuzione del thread corrente. |
8 | IsBackground Ottiene o imposta un valore che indica se un thread è o meno un thread in background. |
9 | IsThreadPoolThread Ottiene un valore che indica se un thread appartiene o meno al pool di thread gestiti. |
10 | ManagedThreadId Ottiene un identificatore univoco per il thread gestito corrente. |
11 | Name Ottiene o imposta il nome del thread. |
12 | Priority Ottiene o imposta un valore che indica la priorità di pianificazione di un thread. |
13 | ThreadState Ottiene un valore contenente gli stati del thread corrente. |
La tabella seguente mostra alcuni dei più usati methods del Thread classe -
Sr.No. | Metodo e descrizione |
---|---|
1 | public void Abort() Genera un'eccezione ThreadAbortException nel thread su cui viene richiamato, per iniziare il processo di terminazione del thread. La chiamata a questo metodo di solito termina il thread. |
2 | public static LocalDataStoreSlot AllocateDataSlot() Alloca uno slot di dati senza nome su tutti i thread. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
3 | public static LocalDataStoreSlot AllocateNamedDataSlot(string name) Alloca uno slot di dati con nome su tutti i thread. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
4 | public static void BeginCriticalRegion() Notifica a un host che l'esecuzione sta per entrare in un'area di codice in cui gli effetti di un'interruzione del thread o di un'eccezione non gestita potrebbero compromettere altre attività nel dominio dell'applicazione. |
5 | public static void BeginThreadAffinity() Notifica a un host che il codice gestito sta per eseguire istruzioni che dipendono dall'identità del thread del sistema operativo fisico corrente. |
6 | public static void EndCriticalRegion() Notifica a un host che l'esecuzione sta per entrare in un'area di codice in cui gli effetti di un'interruzione del thread o di un'eccezione non gestita sono limitati all'attività corrente. |
7 | public static void EndThreadAffinity() Notifica a un host che il codice gestito ha terminato l'esecuzione di istruzioni che dipendono dall'identità del thread del sistema operativo fisico corrente. |
8 | public static void FreeNamedDataSlot(string name) Elimina l'associazione tra un nome e uno slot, per tutti i thread nel processo. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
9 | public static Object GetData(LocalDataStoreSlot slot) Recupera il valore dallo slot specificato nel thread corrente, all'interno del dominio corrente del thread corrente. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
10 | public static AppDomain GetDomain() Restituisce il dominio corrente in cui è in esecuzione il thread corrente. |
11 | public static AppDomain GetDomainID() Restituisce un identificatore di dominio dell'applicazione univoco |
12 | public static LocalDataStoreSlot GetNamedDataSlot(string name) Cerca uno slot di dati denominato. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
13 | public void Interrupt() Interrompe un thread che si trova nello stato del thread WaitSleepJoin. |
14 | public void Join() Blocca il thread chiamante fino al termine di un thread, pur continuando a eseguire il pompaggio COM e SendMessage standard. Questo metodo ha diverse forme di overload. |
15 | public static void MemoryBarrier() Sincronizza l'accesso alla memoria come segue: Il processore che esegue il thread corrente non può riordinare le istruzioni in modo tale che l'accesso alla memoria prima della chiamata a MemoryBarrier venga eseguito dopo gli accessi alla memoria che seguono la chiamata a MemoryBarrier. |
16 | public static void ResetAbort() Annulla un'interruzione richiesta per il thread corrente. |
17 | public static void SetData(LocalDataStoreSlot slot, Object data) Imposta i dati nello slot specificato sul thread attualmente in esecuzione, per il dominio corrente di quel thread. Per prestazioni migliori, utilizza invece i campi contrassegnati con l'attributo ThreadStaticAttribute. |
18 | public void Start() Avvia un thread. |
19 | public static void Sleep(int millisecondsTimeout) Rende il thread in pausa per un periodo di tempo. |
20 | public static void SpinWait(int iterations) Fa sì che un thread attenda il numero di volte definito dal parametro iterations |
21 | public static byte VolatileRead(ref byte address) public static double VolatileRead(ref double address) public static int VolatileRead(ref int address) public static Object VolatileRead(ref Object address) Legge il valore di un campo. Il valore è l'ultimo scritto da qualsiasi processore in un computer, indipendentemente dal numero di processori o dallo stato della cache del processore. Questo metodo ha diverse forme di overload. Solo alcuni sono riportati sopra. |
22 | public static void VolatileWrite(ref byte address,byte value) public static void VolatileWrite(ref double address, double value) public static void VolatileWrite(ref int address, int value) public static void VolatileWrite(ref Object address, Object value) Scrive immediatamente un valore in un campo, in modo che il valore sia visibile a tutti i processori nel computer. Questo metodo ha diverse forme di overload. Solo alcuni sono riportati sopra. |
23 | public static bool Yield() Fa sì che il thread chiamante ceda l'esecuzione a un altro thread pronto per essere eseguito sul processore corrente. Il sistema operativo seleziona il thread a cui cedere. |
Creazione di thread
I thread vengono creati estendendo la classe Thread. La classe Thread estesa chiama quindi ilStart() metodo per iniziare l'esecuzione del thread figlio.
Il seguente programma dimostra il concetto:
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
In Main: Creating the Child thread
Child thread starts
Gestione dei thread
La classe Thread fornisce vari metodi per la gestione dei thread.
L'esempio seguente mostra l'uso di sleep() metodo per fare una pausa del thread per un periodo di tempo specifico.
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
// the thread is paused for 5000 milliseconds
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
Distruggere i fili
Il Abort() viene utilizzato per distruggere i thread.
Il runtime interrompe il thread lanciando un file ThreadAbortException. Questa eccezione non può essere catturato, il controllo viene inviato al infine blocco, se presente.
Il seguente programma lo illustra:
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
try {
Console.WriteLine("Child thread starts");
// do some work, like counting to 10
for (int counter = 0; counter <= 10; counter++) {
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
} catch (ThreadAbortException e) {
Console.WriteLine("Thread Abort Exception");
} finally {
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
//stop the main thread for some time
Thread.Sleep(2000);
//now abort the child
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:
In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception