Csharp Language It
Csharp Language It
#c#
Sommario
Di 1
Osservazioni 2
Versioni 2
Examples 2
Spiegazione 3
Examples 23
Modello semantico 24
Capitolo 3: Accedi alla cartella condivisa di rete con nome utente e password 25
introduzione 25
Examples 25
Examples 28
Connessioni ADO.NET 28
introduzione 32
Sintassi 32
Parametri 32
Osservazioni 32
Da dove veniamo 32
Gli appunti 34
Examples 34
Examples 39
Examples 41
Attributi di convalida 44
Esempio: RequiredAttribute 44
Esempio: StringLengthAttribute 44
Esempio: RangeAttribute 44
Esempio: CustomValidationAttribute 45
uso 46
Contesto di validazione 47
E altro ancora 47
Examples 48
Gli argomenti con nome possono rendere il tuo codice più chiaro 48
Osservazioni 51
Examples 51
Argomenti nominati 51
Argomenti opzionali 54
Sintassi 56
Osservazioni 56
Examples 56
Covarianza di matrice 57
Dichiarare un array 57
Scorrere su un array 58
Matrici multidimensionali 59
Matrici frastagliate 59
Copia di array 62
Uso: 63
Osservazioni 65
Examples 65
[AssemblyTitle] 65
[AssemblyProduct] 65
[AssemblyVersion] 66
Campi comuni 67
[AssemblyConfiguration] 67
[InternalsVisibleTo] 67
[AssemblyKeyFile] 68
introduzione 69
Osservazioni 69
Examples 69
Chiamate contemporanee 71
Examples 77
Utilizzando un attributo 77
Leggere un attributo 77
DebuggerDisplay Attribute 78
Attributo obsoleto 81
Sintassi 82
Osservazioni 82
Examples 82
Osservazioni 86
Quando usare 86
alternative 86
Examples 86
Examples 88
Evitando l'iterazione N * 2 88
Osservazioni 89
Examples 89
Variabili implicitamente tipizzate (var) 89
Espressioni Lambda 90
Tipi anonimi 91
Examples 93
Varianza 94
Sintassi 96
Parametri 96
Osservazioni 96
Examples 96
Async e attesa 96
introduzione 99
Osservazioni 99
Examples 99
Nome dell'operatore 99
Proprietà 101
indicizzatori 102
metodi 102
operatori 103
limitazioni 103
introduzione 108
uso 110
espressioni 115
limitazioni 125
gotchas 125
introduzione 131
Examples 131
Esempio 131
limitazioni 132
Riferimenti 133
h11 137
Riferimenti 139
Funzioni locali 139
Esempio 139
Esempio 140
Esempio 140
is espressione 142
Esempio 142
Restituzione 143
link 144
ValueTask 146
Examples 149
Examples 150
MemoryCache 150
introduzione 151
Sintassi 151
Osservazioni 151
Examples 151
Examples 154
Sintassi 157
Parametri 157
Osservazioni 157
Examples 157
Violazione della regola CLS: eredita dalla classe non CLSComplaint 160
Examples 161
Osservazioni 162
Examples 162
Capitolo 29: Come utilizzare C # Structs per creare un tipo Union (simile a C Unions) 165
Osservazioni 165
Examples 165
Unioni stile C in C # 165
Examples 168
Commenti 168
Regioni 169
Osservazioni 172
Examples 172
Commenti sulla documentazione del metodo con elementi param e resi 173
Parametri 177
Examples 177
Examples 179
Sintassi 182
Osservazioni 182
Examples 182
presupposti 183
postconditions 183
invarianti 183
introduzione 187
Osservazioni 187
Examples 187
Regole 188
interfacce 189
Namespace 190
Enums 190
Utilizzare un nome plurale per i tipi Enum che sono campi bit 190
eccezioni 191
Capitolo 36: Costrutti di flusso di dati di Task Parallel Library (TPL) 192
Examples 192
JoinBlock 192
BroadcastBlock 193
WriteOnceBlock 194
BatchedJoinBlock 195
TransformBlock 195
ActionBlock 196
TransformManyBlock 197
BatchBlock 198
BufferBlock 199
introduzione 201
Osservazioni 201
Examples 201
Capitolo 38: Creazione del proprio MessageBox nell'applicazione Windows Form 211
introduzione 211
Sintassi 211
Examples 211
Come utilizzare il proprio controllo MessageBox creato in un'altra applicazione Windows Fo 213
Capitolo 39: Creazione di un'applicazione console utilizzando un Editor di testo semplice 215
Examples 215
Creazione di un'applicazione console utilizzando un Editor di testo semplice e il compilat 215
Examples 218
Sintassi 239
Osservazioni 239
Examples 239
IsHighResolution 239
Examples 241
Debug.WriteLine 241
Examples 242
Sintassi 246
Osservazioni 246
Espressioni condizionali 246
Examples 247
Linea 249
introduzione 253
Sintassi 253
Osservazioni 253
Examples 253
Prova i valori enum in stile flags con logica bit a bit 256
Sintassi 263
Osservazioni 263
Examples 263
Ereditare da una classe base 263
Examples 274
Gestione degli errori di specifici codici di risposta HTTP (come 404 non trovato) 275
Invio di richiesta HTTP GET asincrona e lettura della richiesta JSON 276
Osservazioni 277
Examples 277
Blocco 277
ConfigureAwait 278
BackgroundWorker 280
Compito 281
Filo 282
Osservazioni 284
Examples 284
Lambdas può essere emesso sia come `Func` che come` Expression` 285
introduzione 288
Parametri 288
Osservazioni 288
Examples 289
introduzione 297
Sintassi 297
Parametri 297
Osservazioni 297
Examples 298
Lettura lenta di un file riga per riga tramite un oggetto IEnumerable 299
Crea file 299
Sintassi 302
Parametri 302
Examples 302
IsFileReady 303
Examples 304
Sintassi 306
Parametri 306
Examples 306
Osservazioni 309
Examples 309
Osservazioni 311
Examples 311
MD5 311
SHA1 312
SHA256 312
SHA384 313
SHA512 313
Examples 319
Sintassi 322
Parametri 322
Osservazioni 322
Examples 322
Generazione della stessa sequenza di numeri casuali più e più volte 323
Osservazioni 325
Examples 325
Produzione: 329
Sintassi 330
Examples 330
Sintassi 331
Parametri 331
Osservazioni 331
Examples 331
Utilizzo del metodo generico con un'interfaccia come tipo di vincolo. 338
covarianza 339
controvarianza 340
invarianza 341
Capitolo 62: Gestione di FormatException durante la conversione di stringhe in altri tipi 347
Examples 347
Examples 349
Osservazioni 351
Examples 351
introduzione 356
Osservazioni 356
Examples 356
Osservazioni 358
Sommario 358
Sintassi 368
Osservazioni 368
Examples 368
Examples 371
introduzione 373
Examples 373
Come implementare il token di reimpostazione della password nell'identità di asp.net utili 373
introduzione 377
Osservazioni 377
Examples 377
IEnumerable 377
Examples 382
Examples 384
Osservazioni 387
Examples 387
Examples 389
Singleton pigro e sicuro per i thread (utilizzando Double Checked Locking) 389
Singleton Lazy, thread safe (per .NET 3.5 o versioni precedenti, implementazione alternati 390
Osservazioni 393
Examples 393
Requisiti 393
Sintassi 397
Osservazioni 397
Examples 397
Osservazioni 400
Examples 400
Sintassi 406
Osservazioni 406
Examples 406
Osservazioni 408
Examples 408
Osservazioni 413
Examples 413
Suggerimento: 417
Nota: 417
Osservazioni 424
Examples 424
Osservazioni 428
Examples 428
Examples 431
Osservazioni 432
Examples 432
Sintassi 440
Osservazioni 440
Examples 440
espressioni 440
Osservazioni 444
Examples 444
Examples 447
ri-lancio 454
serializzazione 454
Conclusione 455
Cheatsheet 460
Osservazioni 465
chiusure 465
Examples 465
introduzione 470
Examples 470
Traccia dello stack per una semplice NullReferenceException in Windows Form 470
Sintassi 472
Examples 472
Sintassi 475
Parametri 475
Examples 475
L'esempio seguente mostra come aprire un archivio zip ed estrarre tutti i file .txt in una 476
Examples 478
Sintassi 480
Examples 482
WithDegreeOfParallelism 482
AsOrdered 482
AsUnordered 483
introduzione 484
Examples 484
Sintassi 489
Osservazioni 489
Examples 490
Examples 497
rompere 498
Continua 502
Examples 503
Examples 506
Examples 512
Sintassi 521
Parametri 521
Osservazioni 521
Examples 522
I metodi di estensione possono vedere solo i membri pubblici (o interni) della classe este 527
Utilizzo dei metodi di estensione per creare bellissime classi di mapping 538
Utilizzo dei metodi di estensione per creare nuovi tipi di raccolta (ad esempio DictList) 540
Examples 542
Osservazioni 545
Examples 545
introduzione 559
Examples 559
Osservazioni 563
Examples 563
pubblico 563
privato 563
interno 564
protetta 564
protetto interno 565
Sintassi 569
Osservazioni 569
Examples 569
introduzione 573
Sintassi 573
Examples 573
Sintassi 578
Osservazioni 578
Examples 578
Examples 583
introduzione 585
Examples 585
Esempio di un metodo generico che ruota un array per un dato turno 585
Examples 587
Examples 588
Sintassi 589
Parametri 589
Osservazioni 589
Examples 589
introduzione 593
Sintassi 593
Parametri 593
Osservazioni 593
Examples 595
taglia di 600
Operatori membri della classe: accesso con membri condizionali nulli 602
tipo di 606
Sintassi 611
Osservazioni 611
Examples 611
Operatore Null-Conditional 611
L'operatore con condizioni null può essere utilizzato con il metodo di estensione 613
Examples 614
String.Trim() 614
introduzione 624
Sintassi 624
Osservazioni 624
Examples 624
introduzione 635
Osservazioni 635
Examples 637
stackalloc 637
volatile 638
fisso 640
predefinito 640
come 642
è 643
tipo di 644
const 644
namespace 646
Continua 648
Etichetta: 651
enum 652
base 653
params 656
rompere 657
astratto 659
galleggiante 660
Doppio 660
decimale 661
uint 661
Questo 662
per 663
mentre 664
ritorno 665
nel 665
utilizzando 666
sigillato 666
taglia di 667
statico 667
svantaggi 669
int 669
lungo 670
ulong 670
dinamico 670
carbonizzare 676
serratura 677
nullo 678
interno 679
dove 680
Gli esempi precedenti mostrano vincoli generici su una definizione di classe, ma i vincoli 682
extern 682
bool 683
quando 683
vuoto 684
Importante notare che se una condizione è soddisfatta nell'esempio precedente, il controll 686
fare 686
operatore 687
struct 689
interruttore 690
interfaccia 691
pericoloso 691
implicito 693
stringa 694
USHORT 695
sbyte 695
var 695
delegare 696
evento 697
parziale 698
introduzione 700
Examples 700
Implementazione C # 700
serializzazione 701
deserializzazione 701
Examples 703
subtyping 705
introduzione 707
Osservazioni 707
Examples 708
Examples 716
Immutabilità 716
introduzione 721
Examples 721
Classi: 721
Osservazioni 722
Examples 722
Dichiarazione 726
Osservazioni 728
Examples 728
void * 730
Examples 732
Introduzione al codice non sicuro 732
introduzione 737
Sintassi 737
Osservazioni 739
Examples 739
Dove 739
Gamma 742
Ripetere 742
Primo() 743
FirstOrDefault () 743
Scorso() 744
LastOrDefault () 744
Singolo () 745
SingleOrDefault () 746
raccomandazioni 746
tranne 747
SelectMany 750
Tutti 751
1. Parametro vuoto 751
Unione 753
SI UNISCE 753
distinto 756
Qualunque 760
ToDictionary 761
Aggregato 762
Definizione di una variabile all'interno di una query Linq (let keyword) 763
SkipWhile 764
DefaultIfEmpty 764
SequenceEqual 765
Seleziona con Func selettore - Utilizzare per ottenere il ranking degli elementi 772
TakeWhile 773
Somma 773
ToLookup 774
Inverso 778
Ordinato da 781
OrderByDescending 781
concat 782
contiene 783
Examples 785
Sintassi 787
Parametri 787
Osservazioni 787
Examples 788
Examples 789
Osservazioni 790
Examples 790
introduzione 797
Osservazioni 797
Examples 797
Ottieni un delegato fortemente digitato su un metodo o una proprietà tramite Reflection 808
Examples 810
Examples 813
RoslynScript 813
CSharpCodeProvider 813
Examples 814
Sintassi 816
Examples 816
Sintassi 817
Osservazioni 817
Examples 817
Osservazioni 820
Examples 820
Examples 830
Osservazioni 832
Examples 832
+ Operatore 832
introduzione 834
Sintassi 834
Parametri 834
Osservazioni 834
Examples 834
Precisione 837
Accordare() 840
Examples 842
Utilizzare StringBuilder per creare una stringa da un numero elevato di record 843
Sintassi 844
Osservazioni 844
Examples 844
Osservazioni 847
Examples 847
Examples 851
Connessione LDAP SSL autenticata, il certificato SSL non corrisponde al DNS inverso 851
Osservazioni 853
Examples 853
Examples 855
Parallel.ForEach 855
Parallel.For 855
Parallel.Invoke 856
Osservazioni 859
Examples 859
Sintassi 869
Osservazioni 869
Examples 869
Caratteristiche: 870
Esempio: utilizzo di un timer per eseguire un semplice conto alla rovescia. 872
Examples 877
Tipo di valore: breve, int, lungo (con segno 16 bit, 32 bit, numeri interi a 64 bit) 877
Tipo di valore: ushort, uint, ulong (interi senza segno a 16 bit, 32 bit, 64 bit) 878
Osservazioni 880
Examples 880
Sintassi 882
Osservazioni 882
introduzione 882
Esistono tipi di valore nello stack, esistono tipi di riferimento sull'heap 883
I tipi di valore non cambiano quando li si cambia in un metodo, i tipi di riferimento lo f 883
I tipi di valore non possono essere nulli, i tipi di riferimento possono 883
Examples 883
Modifica dei valori altrove 883
assegnazione 886
Osservazioni 889
Examples 889
Osservazioni 892
Examples 892
Examples 897
HashSet 897
SortedSet 897
T [] (Matrice di T) 897
Elenco 898
Dizionario 898
Pila 899
Coda 900
Examples 901
introduzione 904
Examples 904
RuntimeSerializer 905
Chiamandolo 906
introduzione 909
Sintassi 909
Osservazioni 909
Examples 909
Gotcha: Eccezione nel metodo Dispose che maschera altri errori in Uso dei blocchi 913
Examples 918
introduzione 924
Examples 924
Examples 927
Examples 930
It is an unofficial and free C# Language ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official C# Language.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/it/home 1
Capitolo 1: Iniziare con C # Language
Osservazioni
C # è un linguaggio di programmazione discendente multi-paradigma di Microsoft. C # è un
linguaggio gestito che compila in CIL , un bytecode intermedio che può essere eseguito su
Windows, Mac OS X e Linux.
Le versioni 1.0, 2.0 e 5.0 sono state standardizzate da ECMA (come ECMA-334 ) e gli sforzi di
standardizzazione per il moderno C # sono in corso.
Versioni
1.0 2002-01-01
1.2 2003-04-01
2.0 2005-09-01
3.0 2007-08-01
4.0 2010-04-01
5.0 2013/06/01
6.0 2015/07/01
7.0 2017/03/07
Examples
Creazione di una nuova applicazione console (Visual Studio)
https://riptutorial.com/it/home 2
System.Console.WriteLine("Hello, World!");
6. Nella barra degli strumenti, fare clic su Debug -> Avvia debug o premere F5 o ctrl + F5 (in
esecuzione senza debugger) per eseguire il programma.
Spiegazione
• class Program è una dichiarazione di classe. Il Program classe 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 Program ha solo un metodo:
Main .
• static void Main() definisce il metodo Main , che è il punto di ingresso per tutti i programmi C
#. Il metodo Main indica cosa fa la classe quando viene eseguita. È consentito un solo
metodo Main per classe.
Per compilare questo esempio, eseguire il seguente comando nella stessa directory in cui si trova
HelloWorld.cs :
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe HelloWorld.cs
Può anche essere possibile che tu abbia due metodi principali all'interno di un'applicazione. In
questo caso, si deve dire al compilatore quale metodo principale per eseguire digitando il
https://riptutorial.com/it/home 3
seguente comando nella console. (Supponiamo classe ClassA ha anche un metodo principale
nello stesso HelloWorld.cs file in HelloWorld namespace)
Nota : questo è il percorso in cui .NET Framework v4.0 si trova in generale. Cambia il percorso in
base alla tua versione .NET. Inoltre, la directory potrebbe essere framework anziché
framework64 se si utilizza .NET Framework a 32 bit. Dal prompt dei comandi di Windows, è
possibile elencare tutti i percorsi del framework csc.exe eseguendo i seguenti comandi (il primo
per i framework a 32 bit):
Ora dovrebbe esserci un file eseguibile denominato HelloWorld.exe nella stessa directory. Per
eseguire il programma dal prompt dei comandi, digita semplicemente il nome del file eseguibile e
premi Invio come segue:
HelloWorld.exe
Questo produrrà:
Ciao mondo!
È anche possibile fare doppio clic sul file eseguibile e avviare una nuova finestra della console con
il messaggio " Hello, world! "
https://riptutorial.com/it/home 4
Creazione di un nuovo progetto in Visual Studio (applicazione console) ed
esecuzione in modalità Debug
1. Scarica e installa Visual Studio . Visual Studio può essere scaricato da VisualStudio.com .
L'edizione comunitaria è suggerita, in primo luogo perché è gratuita e in secondo luogo
perché include tutte le funzionalità generali e può essere estesa ulteriormente.
https://riptutorial.com/it/home 5
5. Dopo aver selezionato Applicazione console, immettere un nome per il progetto e una
posizione da salvare e premere OK . Non preoccuparti del nome della soluzione.
https://riptutorial.com/it/home 6
https://riptutorial.com/it/home 7
(Utilizzare sempre nomi descrittivi per i progetti in modo che possano essere facilmente
distinti da altri progetti. Si consiglia di non utilizzare spazi nel nome del progetto o della
classe.)
7. Scrivi il codice Ora puoi aggiornare Program.cs per presentare "Hello world!" per l'utente.
using System;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
}
}
}
Aggiungi le seguenti due righe all'oggetto public static void Main(string[] args) in
Program.cs : (assicurati che sia all'interno delle parentesi graffe)
Console.WriteLine("Hello world!");
Console.Read();
Perché Console.Read() ? La prima riga stampa il testo "Hello world!" alla console, e la
seconda linea attende l'immissione di un singolo carattere; in effetti, questo fa in modo che il
programma interrompa l'esecuzione in modo che tu possa vedere l'output durante il debug.
Senza Console.Read(); , quando avvii il debug dell'applicazione, verrà semplicemente
stampato "Hello world!" alla console e quindi chiudere immediatamente. La finestra del
codice dovrebbe ora apparire come la seguente:
using System;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello world!");
Console.Read();
}
}
}
8. Esegui il debug del tuo programma. Premi il pulsante Start sulla barra degli strumenti
vicino alla parte superiore della finestra o premere F5 sulla tastiera per eseguire
l'applicazione. Se il pulsante non è presente, è possibile eseguire il programma dal menu
principale: Debug → Avvia debug . Il programma compilerà e quindi aprirà una finestra
della console. Dovrebbe apparire simile allo screenshot seguente:
https://riptutorial.com/it/home 8
9. Ferma il programma. Per chiudere il programma, basta premere un tasto qualsiasi sulla
tastiera. La Console.Read() abbiamo aggiunto era per lo stesso scopo. Un altro modo per
chiudere il programma è andare nel menu in cui si trovava il pulsante Start e fare clic sul
pulsante Stop .
Innanzitutto installa Mono seguendo le istruzioni di installazione per la piattaforma scelta come
descritto nella relativa sezione di installazione .
Se si utilizza Windows, eseguire il Prompt dei comandi mono incluso nell'installazione di Mono e
assicurarsi che siano impostate le variabili di ambiente necessarie. Se su Mac o Linux, apri un
nuovo terminale.
Per compilare il file appena creato, eseguire il seguente comando nella directory contenente
HelloWorld.cs
https://riptutorial.com/it/home 9
:
mono HelloWorld.exe
Hello, world!
Press any key to exit..
Innanzitutto installa .NET Core SDK seguendo le istruzioni di installazione per la piattaforma di
tua scelta:
• finestre
• OSX
• Linux
• docker
1. Crea una nuova directory con mkdir hello_world e cambia nella directory appena creata con
cd hello_world .
• hello_world.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>
• Program.cs
using System;
namespace hello_world
{
class Program
{
static void Main(string[] args)
https://riptutorial.com/it/home 10
{
Console.WriteLine("Hello World!");
}
}
}
4. Facoltativo Crea l'applicazione con dotnet build per Debug o dotnet build -c Release for
Release. dotnet run eseguirà anche il compilatore e genererà errori di compilazione, se
presenti.
https://riptutorial.com/it/home 11
Creare una nuova query usando LinqPad
LinqPad è un ottimo strumento che ti consente di apprendere e testare le funzionalità dei linguaggi
.Net (C #, F # e VB.Net.)
1. Installa LinqPad
https://riptutorial.com/it/home 12
4. Digita il codice seguente e premi run ( F5 )
https://riptutorial.com/it/home 13
6. Ora che hai creato il tuo primo programma .Net, vai e controlla gli esempi inclusi in LinqPad
tramite il browser "Samples". Ci sono molti ottimi esempi che ti mostreranno molte
caratteristiche differenti dei linguaggi .Net.
https://riptutorial.com/it/home 14
Gli appunti:
1. Se si fa clic su "IL", è possibile controllare il codice IL generato dal codice .net. Questo è un
grande strumento di apprendimento.
https://riptutorial.com/it/home 15
2. Quando si utilizza LINQ to SQL o Linq to Entities è possibile esaminare l'SQL generato, un
altro ottimo modo per conoscere LINQ.
https://riptutorial.com/it/home 16
4. Fare clic su .NET → Progetto console e selezionare C # .
5. Fare clic su Avanti per procedere.
https://riptutorial.com/it/home 17
6. Immettere il nome del progetto e Sfoglia ... per una posizione da salvare, quindi fare clic
su Crea .
https://riptutorial.com/it/home 18
7. Il progetto appena creato sarà simile a:
https://riptutorial.com/it/home 19
8. Questo è il codice nell'editor di testo:
using System;
namespace FirstCsharp
{
public class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
https://riptutorial.com/it/home 20
}
9. Per eseguire il codice, premi F5 o fai clic sul pulsante Riproduci come mostrato di seguito:
https://riptutorial.com/it/home 21
Leggi Iniziare con C # Language online: https://riptutorial.com/it/csharp/topic/15/iniziare-con-c-
sharp-language
https://riptutorial.com/it/home 22
Capitolo 2: .NET Compiler Platform (Roslyn)
Examples
Crea spazio di lavoro dal progetto MSBuild
Per caricare il codice esistente nello spazio di lavoro, compilare e segnalare errori.
Successivamente il codice sarà localizzato in memoria. Da qui, saranno disponibili sia il lato
sintattico che quello semantico con cui lavorare.
Un Syntax Tree è una struttura di dati immutabile che rappresenta il programma come un albero
di nomi, comandi e segni (come precedentemente configurato nell'editor).
Nell'edificio della sintassi esisteranno tutti i tipi di costrutti C # con un tipo corrispondente. Per
trovare rapidamente tipi specifici, utilizzare la finestra Syntax Visualizer di Visual Studio. Questo
interpreterà il documento aperto corrente come un albero di sintassi di Roslyn.
https://riptutorial.com/it/home 23
Modello semantico
Un modello semantico offre un livello più profondo di interpretazione e intuizione del codice
rispetto a un albero di sintassi. Laddove gli alberi di sintassi possono indicare i nomi delle variabili,
i modelli semantici forniscono anche il tipo e tutti i riferimenti. Le chiamate del metodo di avviso
degli alberi di sintassi, ma i modelli semantici forniscono riferimenti alla posizione precisa in cui è
stato dichiarato il metodo (dopo che è stata applicata la risoluzione di sovraccarico).
Console.WriteLine(variableSymbol.Type);
// => "Microsoft.CodeAnalysis.SyntaxNode"
Questo produce un elenco di variabili locali usando un albero di sintassi. Quindi consulta il
modello semantico per ottenere il nome completo del tipo e trova tutti i riferimenti di ogni variabile.
https://riptutorial.com/it/home 24
Capitolo 3: Accedi alla cartella condivisa di
rete con nome utente e password
introduzione
Accesso al file di condivisione di rete tramite PInvoke.
Examples
Codice per accedere al file condiviso di rete
if (result != 0)
{
throw new Win32Exception(result);
}
}
~NetworkConnection()
{
Dispose(false);
}
https://riptutorial.com/it/home 25
}
[DllImport("mpr.dll")]
private static extern int WNetAddConnection2(NetResource netResource,
string password, string username, int flags);
[DllImport("mpr.dll")]
private static extern int WNetCancelConnection2(string name, int flags,
bool force);
}
[StructLayout(LayoutKind.Sequential)]
public class NetResource
{
public ResourceScope Scope;
public ResourceType ResourceType;
public ResourceDisplaytype DisplayType;
public int Usage;
public string LocalName;
public string RemoteName;
public string Comment;
public string Provider;
}
https://riptutorial.com/it/home 26
Leggi Accedi alla cartella condivisa di rete con nome utente e password online:
https://riptutorial.com/it/csharp/topic/9627/accedi-alla-cartella-condivisa-di-rete-con-nome-utente-
e-password
https://riptutorial.com/it/home 27
Capitolo 4: Accesso ai database
Examples
Connessioni ADO.NET
Le connessioni ADO.NET sono uno dei modi più semplici per connettersi a un database da
un'applicazione C #. Si basano sull'utilizzo di un provider e di una stringa di connessione che
punta al database per eseguire query contro.
Tutti questi sono comunemente usati per accedere ai dati tramite C # e verranno comunemente
riscontrati durante la creazione di applicazioni incentrate sui dati. FooDataReader si può aspettare
che molte altre classi che non sono menzionate che implementano le stesse FooConnection ,
FooCommand , FooDataReader si comportino allo stesso modo.
https://riptutorial.com/it/home 28
O se stavi semplicemente eseguendo un semplice aggiornamento e non avessi bisogno di un
lettore, si applicherebbe lo stesso concetto di base:
È anche possibile programmare contro una serie di interfacce comuni e non doversi preoccupare
delle classi specifiche del provider. Le interfacce principali fornite da ADO.NET sono:
Entity Framework espone le classi di astrazione utilizzate per interagire con i database sottostanti
sotto forma di classi come DbContext . Questi contesti generalmente sono costituiti da proprietà
DbSet<T> che espongono le raccolte disponibili che possono essere interrogate:
https://riptutorial.com/it/home 29
public class ExampleContext: DbContext
{
public virtual DbSet<Widgets> Widgets { get; set; }
}
Lo stesso DbContext gestirà le connessioni con i database e in genere leggerà i dati della stringa di
connessione appropriata da una configurazione per determinare come stabilire le connessioni:
Entity Framework fornisce inoltre un ampio sistema di tracciabilità delle modifiche che può essere
utilizzato per gestire le voci di aggiornamento all'interno del database semplicemente chiamando il
metodo SaveChanges() per inviare modifiche al database:
Stringhe di connessione
Una stringa di connessione è una stringa che specifica le informazioni su una particolare fonte di
dati e come procedere per connettersi ad essa memorizzando credenziali, posizioni e altre
https://riptutorial.com/it/home 30
informazioni.
Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
<connectionStrings>
<add name="WidgetsContext" providerName="System.Data.SqlClient"
connectionString="Server=.\SQLEXPRESS;Database=Widgets;Integrated Security=True;"/>
</connectionStrings>
<connectionStrings>
<add name="WidgetsContext" providerName="System.Data.SqlClient"
connectionString="Server=.\SQLEXPRESS;Database=Widgets;Integrated Security=SSPI;"/>
</connectionStrings>
Ciò consentirà alla tua applicazione di accedere alla stringa di connessione in modo
programmatico tramite WidgetsContext . Sebbene sia Integrated Security=SSPI e Integrated
Security=True svolgono la stessa funzione; Integrated Security=SSPI è preferito poiché funziona
con entrambi i provider SQLClient e OleDB, dove come Integrated Security=true genera
un'eccezione quando utilizzato con il provider OleDb.
https://riptutorial.com/it/home 31
Capitolo 5: Alberi di espressione
introduzione
Gli alberi di espressione sono espressioni disposte in una struttura di dati simile a un albero. Ogni
nodo nell'albero è una rappresentazione di un'espressione, un'espressione essendo un codice.
Una rappresentazione in memoria di un'espressione Lambda sarebbe un albero di espressione,
che contiene gli elementi effettivi (cioè il codice) della query, ma non il suo risultato. Gli alberi di
espressione rendono la struttura di un'espressione lambda trasparente ed esplicita.
Sintassi
• Espressione <TDelegate> name = lambdaExpression;
Parametri
Parametro Dettagli
Osservazioni
https://riptutorial.com/it/home 32
Gli alberi di espressione sono strutture di dati in un formato di un albero, in cui ogni nodo contiene
un'espressione. Sono utilizzati per tradurre le istruzioni compilate (come i metodi utilizzati per
filtrare i dati) in espressioni che potrebbero essere utilizzate al di fuori dell'ambiente del
programma, come all'interno di una query del database.
Il problema qui è che una query remota non può accedere al nostro metodo . Potremmo evitare
questo problema se, invece, abbiamo inviato le istruzioni per il metodo alla query remota. Nel
nostro esempio CalculateTotalTaxDue , ciò significa che inviamo queste informazioni:
Con queste istruzioni, la query remota può eseguire il lavoro mentre crea i dati.
Ci sono due sfide per l'implementazione di questo. Come si trasforma un metodo .NET compilato
in un elenco di istruzioni e come si formattano le istruzioni in modo che possano essere utilizzate
dal sistema remoto?
Senza alberi di espressione, è possibile risolvere solo il primo problema con MSIL. (MSIL è il
codice simile all'assembler creato dal compilatore .NET). L'analisi di MSIL è possibile , ma non è
facile. Anche quando lo si analizza correttamente, può essere difficile determinare quale fosse
l'intento del programmatore originale con una particolare routine.
https://riptutorial.com/it/home 33
Le espressioni Lambda non possono creare ogni tipo di albero delle espressioni. In questi casi, è
possibile utilizzare manualmente l'API di espressioni per creare l'albero necessario. Nell'esempio
Comprendere le espressioni API , creiamo l'espressione CalculateTotalSalesTax utilizzando l'API.
NOTA: i nomi diventano un po 'confusi qui. Un'espressione lambda (due parole, in minuscolo) si
riferisce al blocco di codice con un indicatore => . Rappresenta un metodo anonimo in C # e viene
convertito in un Delegate o in Expression . A LambdaExpression (una parola, PascalCase) fa
riferimento al tipo di nodo all'interno dell'API di espressione che rappresenta un metodo che è
possibile eseguire.
Mettendo insieme tutti i pezzi, puoi vedere il vero potere dietro LINQ.
1. Scrivi una query usando un'espressione lambda: products.Where(x => x.Cost > 5)
2. Il compilatore trasforma quell'espressione in un albero di espressioni con le istruzioni
"controlla se la proprietà Cost del parametro è maggiore di cinque".
3. Il provider di query analizza la struttura dell'espressione e produce una query SQL valida
SELECT * FROM products WHERE Cost > 5
4. L'ORM proietta tutti i risultati in POCO e ottieni un elenco di oggetti
Gli appunti
• Gli alberi delle espressioni sono immutabili. Se si desidera modificare un albero di
espressioni è necessario crearne uno nuovo, copiare quello esistente in quello nuovo (per
attraversare un albero di espressioni è possibile utilizzare ExpressionVisitor ) e apportare le
modifiche desiderate.
Examples
Creazione di alberi di espressione mediante l'API
using System.Linq.Expressions;
https://riptutorial.com/it/home 34
new ParameterExpression[] { numParam });
// Call the Compile method on the expression tree to return a delegate that can be called.
Func<int, bool> result = expr.Compile();
// Prints True.
// You can also combine the compile step with the call/invoke step as below:
Console.WriteLine(expr.Compile()(4));
using System.Linq.Expressions;
Per creare alberi di espressioni 'a mano', si dovrebbe usare la classe Expression .
https://riptutorial.com/it/home 35
Comprendere l'API delle espressioni
Utilizzeremo l'albero delle espressioni API per creare un albero CalculateSalesTax . In inglese
semplice, ecco un riepilogo dei passaggi necessari per creare l'albero.
//For reference, we're using the API to build this lambda expression
orderLine => orderLine.IsTaxable ? orderLine.Total * orderLine.Order.TaxRate : 0;
//The orderLine parameter we pass in to the method. We specify it's type (OrderLine) and the
name of the parameter.
ParameterExpression orderLine = Expression.Parameter(typeof(OrderLine), "orderLine");
//Check if the parameter is taxable; First we need to access the is taxable property, then
check if it's true
PropertyInfo isTaxableAccessor = typeof(OrderLine).GetProperty("IsTaxable");
MemberExpression getIsTaxable = Expression.MakeMemberAccess(orderLine, isTaxableAccessor);
UnaryExpression isLineTaxable = Expression.IsTrue(getIsTaxable);
//Get the tax rate - notice that we pass the getOrder expression directly to the member
access
PropertyInfo taxRateAccessor = typeof(Order).GetProperty("TaxRate");
MemberExpression getTaxRate = Expression.MakeMemberAccess(getOrder, taxRateAccessor);
//Multiply the two - notice we pass the two operand expressions directly to multiply
BinaryExpression multiplyTotalByRate = Expression.Multiply(getTotal, getTaxRate);
//If the line is not taxable, we'll return a constant value - 0.0 (decimal)
ConstantExpression zero = Expression.Constant(0M);
Gli alberi di espressione rappresentano il codice in una struttura dati ad albero, in cui ogni nodo è
un'espressione
https://riptutorial.com/it/home 36
Expression Trees consente la modifica dinamica del codice eseguibile, l'esecuzione di query LINQ
in vari database e la creazione di query dinamiche. È possibile compilare ed eseguire codice
rappresentato da alberi di espressione.
Questi vengono anche utilizzati nel linguaggio dinamico run-time (DLR) per fornire l'interoperabilità
tra i linguaggi dinamici e .NET Framework e per consentire ai produttori di compilatori di emettere
alberi di espressioni anziché il linguaggio intermedio Microsoft (MSIL).
Quando un'espressione lambda viene assegnata alla variabile di tipo Expression, il compilatore
emette il codice per creare un albero di espressioni che rappresenti l'espressione lambda.
I seguenti esempi di codice mostrano come fare in modo che il compilatore C # crei un albero di
espressioni che rappresenti l'espressione lambda num => num <5.
Alberi di espressione creati anche usando la classe di espressione . Questa classe contiene
metodi factory statici che creano nodi di albero dell'espressione di tipi specifici.
1. ParameterExpression
2. MethodCallExpression
Il seguente esempio di codice mostra come creare un albero di espressioni che rappresenti
l'espressione lambda num => num <5 utilizzando l'API.
Definisci una nuova classe di visitatori sovrascrivendo alcuni dei metodi di ExpressionVisitor :
https://riptutorial.com/it/home 37
}
protected override Expression VisitParameter(ParameterExpression node) {
Console.WriteLine("Parameter: {0}", node);
return base.VisitParameter(node);
}
protected override Expression VisitBinary(BinaryExpression node) {
Console.WriteLine("Binary with operator {0}", node.NodeType);
return base.VisitBinary(node);
}
}
https://riptutorial.com/it/home 38
Capitolo 6: Alias di tipi predefiniti
Examples
Tabella dei tipi incorporati
La tabella seguente mostra le parole chiave per i tipi di C# incorporati, che sono alias di tipi
predefiniti negli spazi dei nomi di sistema.
bool System.Boolean
byte System.Byte
sbyte System.SByte
carbonizzare System.Char
decimale System.Decimal
Doppio System.Double
galleggiante System.Single
int System.Int32
uint System.UInt32
lungo System.Int64
ulong System.UInt64
oggetto System.Object
corto System.Int16
USHORT System.UInt16
stringa System.String
Le parole chiave di tipo C# e i loro alias sono intercambiabili. Ad esempio, è possibile dichiarare
una variabile intera utilizzando una delle seguenti dichiarazioni:
https://riptutorial.com/it/home 39
Leggi Alias di tipi predefiniti online: https://riptutorial.com/it/csharp/topic/1862/alias---di-tipi-
predefiniti
https://riptutorial.com/it/home 40
Capitolo 7: Annotazione dei dati
Examples
DisplayNameAttribute (attributo di visualizzazione)
DisplayNameimposta il nome visualizzato per un metodo property, event o public void con
argomenti zero (0).
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication="clr-namespace:WpfApplication"
Height="100" Width="360" Title="Display name example">
<Window.Resources>
<wpfApplication:DisplayNameConverter x:Key="DisplayNameConverter"/>
</Window.Resources>
<StackPanel Margin="5">
<!-- Label (DisplayName attribute) -->
<Label Content="{Binding Employee, Converter={StaticResource DisplayNameConverter},
ConverterParameter=FirstName}" />
<!-- TextBox (FirstName property value) -->
<TextBox Text="{Binding Employee.FirstName, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Window>
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Employee _employee = new Employee();
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
https://riptutorial.com/it/home 41
public Employee Employee
{
get { return _employee; }
set { _employee = value; }
}
}
}
namespace WpfApplication
{
public class DisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo
culture)
{
// Get display name for given instance type and property name
var attribute = value.GetType()
.GetProperty(parameter.ToString())
.GetCustomAttributes(false)
.OfType<DisplayNameAttribute>()
.FirstOrDefault();
EditableAttribute stabilisce se gli utenti devono essere in grado di modificare il valore della
proprietà della classe.
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
https://riptutorial.com/it/home 42
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication="clr-namespace:WpfApplication"
Height="70" Width="360" Title="Display name example">
<Window.Resources>
<wpfApplication:EditableConverter x:Key="EditableConverter"/>
</Window.Resources>
<StackPanel Margin="5">
<!-- TextBox Text (FirstName property value) -->
<!-- TextBox IsEnabled (Editable attribute) -->
<TextBox Text="{Binding Employee.FirstName, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Employee, Converter={StaticResource EditableConverter},
ConverterParameter=FirstName}"/>
</StackPanel>
</Window>
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Employee _employee = new Employee() { FirstName = "This is not editable"};
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
namespace WpfApplication
{
public class EditableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo
culture)
{
// return editable attribute's value for given instance property,
// defaults to true if not found
var attribute = value.GetType()
.GetProperty(parameter.ToString())
.GetCustomAttributes(false)
.OfType<EditableAttribute>()
.FirstOrDefault();
https://riptutorial.com/it/home 43
}
Attributi di convalida
Gli attributi di convalida vengono utilizzati per applicare varie regole di convalida in modo
dichiarativo su classi o membri della classe. Tutti gli attributi di convalida derivano dalla classe
base ValidationAttribute .
Esempio: RequiredAttribute
Se convalidato tramite il metodo ValidationAttribute.Validate , questo attributo restituirà un errore
se la proprietà Name è null o contiene solo spazi.
Esempio: StringLengthAttribute
StringLengthAttributeconvalida se una stringa è inferiore alla lunghezza massima di una stringa.
Può facoltativamente specificare una lunghezza minima. Entrambi i valori sono inclusi.
Esempio: RangeAttribute
RangeAttribute fornisce il valore massimo e minimo per un campo numerico.
https://riptutorial.com/it/home 44
public class Model
{
[Range(0.01, 100.00,ErrorMessage = "Price must be between 0.01 and 100.00")]
public decimal Price { get; set; }
}
Esempio: CustomValidationAttribute
La classe CustomValidationAttribute consente di richiamare un metodo static personalizzato per la
convalida. Il metodo personalizzato deve essere static ValidationResult [MethodName] (object
input) .
if (input?.ToString()?.ToUpperInvariant() == "APPLE")
{
result = new ValidationResult("Apples are not allowed.");
}
return result;
}
}
Gli attributi di convalida personalizzati possono essere creati derivando dalla classe di base
ValidationAttribute , quindi sovrascrivendo virtual metodi virtual secondo necessità.
if (!string.IsNullOrEmpty(inputValue))
{
isValid = inputValue.ToUpperInvariant() != "BANANA";
}
https://riptutorial.com/it/home 45
return isValid;
}
}
Le annotazioni dei dati sono un modo per aggiungere più informazioni contestuali alle classi o ai
membri di una classe. Esistono tre categorie principali di annotazioni:
uso
Ecco un esempio in cui vengono utilizzati due ValidationAttribute e uno DisplayAttribute :
class Kid
{
[Range(0, 18)] // The age cannot be over 18 and cannot be negative
public int Age { get; set; }
[StringLength(MaximumLength = 50, MinimumLength = 3)] // The name cannot be under 3 chars
or more than 50 chars
public string Name { get; set; }
[DataType(DataType.Date)] // The birthday will be displayed as a date only (without the
time)
public DateTime Birthday { get; set; }
}
Le annotazioni dei dati sono utilizzate principalmente in framework come ASP.NET. Ad esempio,
in ASP.NET MVC , quando un modello viene ricevuto da un metodo controller, ModelState.IsValid()
può essere utilizzato per determinare se il modello ricevuto rispetta tutto il suo ValidationAttribute
. DisplayAttribute viene anche utilizzato in ASP.NET MVC per determinare come visualizzare i valori
su una pagina Web.
La maggior parte delle volte, gli attributi di convalida sono utilizzati all'interno di framework (come
ASP.NET). Questi framework si occupano dell'esecuzione degli attributi di convalida. Ma cosa
succede se si desidera eseguire manualmente gli attributi di convalida? Basta usare la classe
Validator (nessuna riflessione necessaria).
https://riptutorial.com/it/home 46
Contesto di validazione
Qualsiasi convalida necessita di un contesto per fornire alcune informazioni su ciò che viene
convalidato. Questo può includere varie informazioni come l'oggetto da convalidare, alcune
proprietà, il nome da visualizzare nel messaggio di errore, ecc.
Una volta creato il contesto, ci sono molti modi per fare la convalida.
E altro ancora
Per saperne di più sulla convalida manuale vedi:
https://riptutorial.com/it/home 47
Capitolo 8: Argomenti nominati
Examples
Gli argomenti con nome possono rendere il tuo codice più chiaro
class SmsUtil
{
public bool SendMessage(string from, string to, string message, int retryCount, object
attachment)
{
// Some code
}
}
puoi rendere questo metodo ancora più chiaro con gli argomenti con nome :
Quando si desidera chiamare questo metodo senza impostare retryCount argomento retryCount :
https://riptutorial.com/it/home 48
message : "Hello there!",
attachment : new object());
Metodo di esempio:
Chiama il campione:
Console.WriteLine (Sample(left:"A",right:"B"));
Console.WriteLine (Sample(right:"A",left:"B"));
risultati:
A-B
B-A
Usa sempre gli argomenti con nome sui parametri facoltativi, per evitare potenziali bug quando il
metodo viene modificato.
class Employee
{
public string Name { get; private set; }
Il codice sopra compila e funziona bene, finché il costruttore non viene cambiato un giorno come:
https://riptutorial.com/it/home 49
this.Title = title;
}
//the below code still compiles, but now "Associate" is an argument of "department"
var jack = new Employee("Jack", "Associate");
Le migliori pratiche per evitare errori quando "qualcun altro nel team" ha commesso degli errori:
https://riptutorial.com/it/home 50
Capitolo 9: Argomenti nominati e opzionali
Osservazioni
Argomenti nominati
Rif: MSDN Gli argomenti con nome consentono di specificare un argomento per un particolare
parametro associando l'argomento al nome del parametro anziché con la posizione del parametro
nell'elenco dei parametri.
Argomenti opzionali
Rif: MSDN La definizione di un metodo, costruttore, indicizzatore o delegato può specificare che i
suoi parametri sono obbligatori o che sono facoltativi. Ogni chiamata deve fornire argomenti per
tutti i parametri richiesti, ma può omettere argomenti per i parametri facoltativi.
Examples
Argomenti nominati
FindArea(120, 56);
In questo il nostro primo argomento è la lunghezza (cioè 120) e il secondo argomento è larghezza
https://riptutorial.com/it/home 51
(cioè 56). E stiamo calcolando l'area con quella funzione. E di seguito è la definizione della
funzione.
Quindi nella prima chiamata di funzione, abbiamo appena passato gli argomenti per la sua
posizione. Destra?
double area;
Console.WriteLine("Area with positioned argument is: ");
area = FindArea(120, 56);
Console.WriteLine(area);
Console.Read();
Ora ecco le caratteristiche di un argomento con nome. Si prega di consultare la chiamata alla
funzione precedente.
https://riptutorial.com/it/home 52
Qui stiamo dando gli argomenti nominati nella chiamata al metodo.
Ora se si esegue questo programma, si otterrà lo stesso risultato. Possiamo dare i nomi vice
versa nella chiamata al metodo se stiamo usando gli argomenti con nome.
Uno degli usi importanti di un argomento con nome è che quando lo usi nel tuo programma
migliora la leggibilità del tuo codice. Dice semplicemente quale dovrebbe essere la tua
argomentazione o cosa è?
Puoi anche dare gli argomenti posizionali. Ciò significa, una combinazione di entrambi gli
argomenti posizionali e argomento con nome.
Nell'esempio precedente abbiamo passato 120 come lunghezza e 56 come argomento con nome
per la larghezza del parametro.
La specifica dell'argomento con nome deve apparire dopo che sono stati specificati tutti gli
argomenti fissi.
Se si usa un argomento con nome prima di un argomento fisso, si otterrà un errore in fase di
compilazione come segue.
La specifica dell'argomento con nome deve apparire dopo che sono stati specificati tutti gli
argomenti fissi
https://riptutorial.com/it/home 53
Argomenti opzionali
Qui abbiamo impostato il valore per width come facoltativo e abbiamo dato valore come 56. Se si
nota, lo stesso IntelliSense mostra l'argomento opzionale come mostrato nell'immagine
sottostante.
Nota che non abbiamo ricevuto alcun errore durante la compilazione e ti forniremo un output come
segue.
https://riptutorial.com/it/home 54
Un altro modo per implementare l'argomento facoltativo è utilizzare la parola chiave [Optional] .
Se non si passa il valore per l'argomento facoltativo, il valore predefinito di tale tipo di dati viene
assegnato a tale argomento. La parola chiave Optional è presente nello spazio dei nomi
"Runtime.InteropServices".
using System.Runtime.InteropServices;
private static double FindAreaWithOptional(int length, [Optional]int width)
{
try
{
return (length * width);
}
catch (Exception)
{
throw new NotImplementedException();
}
}
E quando chiamiamo la funzione, otteniamo 0 perché il secondo argomento non viene passato e il
valore predefinito di int è 0 e quindi il prodotto è 0.
https://riptutorial.com/it/home 55
Capitolo 10: Array
Sintassi
• Dichiarazione di un array:
<tipo> [] <nome>;
<Nome> [i]
<Nome> .Length
Osservazioni
In C #, un array è un tipo di riferimento, il che significa che è nullable .
Un array ha una lunghezza fissa, il che significa che non puoi .Add() ad esso o .Remove() da esso.
Per poterli utilizzare, è necessario un array dinamico: List o ArrayList .
Examples
https://riptutorial.com/it/home 56
Covarianza di matrice
Questa conversione non è sicura dal testo. Il seguente codice genererà un'eccezione di runtime:
// Get
Console.WriteLine(arr[2]); // 20
// Set
arr[2] = 100;
Dichiarare un array
Un array può essere dichiarato e riempito con il valore predefinito usando la sintassi di
inizializzazione parentesi quadra ( [] ). Ad esempio, creando un array di 10 numeri interi:
Gli indici in C # sono a base zero. Gli indici dell'array sopra saranno 0-9. Per esempio:
Il che significa che il sistema inizia a contare l'indice degli elementi da 0. Inoltre, gli accessi agli
elementi degli array vengono eseguiti in un tempo costante . Ciò significa che l'accesso al primo
elemento dell'array ha lo stesso costo (nel tempo) dell'accesso al secondo elemento, al terzo
elemento e così via.
Un array può anche essere creato e inizializzato con valori personalizzati utilizzando la sintassi di
https://riptutorial.com/it/home 57
inizializzazione della raccolta:
La new int[] porzione new int[] può essere omessa quando si dichiara una variabile di array.
Questa non è un'espressione autonoma, quindi utilizzarla come parte di una chiamata diversa non
funziona (per questo, usa la versione con una new ):
In alternativa, in combinazione con la parola chiave var , il tipo specifico può essere omesso in
modo da inferire il tipo della matrice:
// same as int[]
var arr = new [] { 1, 2, 3 };
// same as string[]
var arr = new [] { "one", "two", "three" };
// same as double[]
var arr = new [] { 1.0, 2.0, 3.0 };
Scorrere su un array
utilizzando foreach:
unsafe
{
int length = arr.Length;
fixed (int* p = arr)
{
int* pInt = p;
while (length-- > 0)
{
Console.WriteLine(*pInt);
https://riptutorial.com/it/home 58
pInt++;// move pointer to next element
}
}
}
Produzione:
1
6
3
3
9
Matrici multidimensionali
Le matrici possono avere più di una dimensione. Nell'esempio seguente viene creato un array
bidimensionale di dieci righe e dieci colonne:
int[,] arr = new int[4, 2] { {1, 1}, {2, 2}, {3, 3}, {4, 4} };
Matrici frastagliate
Gli array frastagliati sono array che invece di tipi primitivi contengono array (o altre raccolte). È
come un array di array: ogni elemento dell'array contiene un altro array.
Sono simili agli array multidimensionali, ma presentano una leggera differenza: poiché gli array
multidimensionali sono limitati a un numero fisso di righe e colonne, con matrici frastagliate, ogni
riga può avere un numero diverso di colonne.
Il secondo [] viene inizializzato senza un numero. Per inizializzare i sottoarray, è necessario farlo
separatamente:
https://riptutorial.com/it/home 59
for (int i = 0; i < a.length; i++)
{
a[i] = new int[10];
}
Ora, ottenere uno dei sottotitoli è facile. Stampiamo tutti i numeri della 3a colonna di a :
a[<row_number>][<column_number>]
a[<row_number>][<column_number>] = <value>
Ricorda : è sempre consigliabile utilizzare matrici frastagliate (matrici di matrici) piuttosto che
array multidimensionali (matrici). È più veloce e più sicuro da usare.
Nel sistema tipo CLR, la convenzione per l'ordinamento delle staffe è invertita, quindi con quanto
sopra arr esempio abbiamo:
arr.GetType().ToString() == "System.Int32[][,,,,][,,]"
typeof(int[,,][,,,,][]).ToString() == "System.Int32[][,,,,][,,]"
https://riptutorial.com/it/home 60
return false;
/// Campione
Questo creerà una matrice di 10 numeri interi con ogni elemento dell'array che ha valore 0 (il
valore predefinito di tipo int ).
Per creare un array inizializzato con un valore non predefinito, è possibile utilizzare
Enumerable.Repeat dallo System.Linq nomi System.Linq :
https://riptutorial.com/it/home 61
bool[] booleanArray = Enumerable.Repeat(true, 10).ToArray();
3. Per creare una serie di string di dimensione 5 riempita con "C #"
Copia di array
Copia di una matrice parziale con il metodo statico Array.Copy() , a partire dall'indice 0 in entrambi,
origine e destinazione:
Copia l'intero array con il metodo di istanza CopyTo() , iniziando dall'indice 0 dell'origine e
dall'indice specificato nella destinazione:
Sia CopyTo che Clone eseguono una copia superficiale che significa che il contenuto contiene
riferimenti allo stesso oggetto degli elementi nell'array originale.
LINQ fornisce un metodo che semplifica la creazione di una raccolta piena di numeri sequenziali.
Ad esempio, è possibile dichiarare una matrice che contiene gli interi tra 1 e 100.
Il metodo Enumerable.Range ci consente di creare una sequenza di numeri interi da una posizione
iniziale specificata e un numero di elementi.
https://riptutorial.com/it/home 62
Enumerable.Range(int start, int count)
Uso:
Questo genererà un array contenente i numeri da 1 a 100 ( [1, 2, 3, ..., 98, 99, 100] ).
Poiché il metodo Range restituisce un oggetto IEnumerable<int> , possiamo utilizzare altri metodi
LINQ su di esso:
Questo genererà una matrice che contiene 10 numeri interi a partire da 4 : [4, 9, 16, ..., 100,
121] .
LINQ fornisce una funzione integrata per il controllo dell'uguaglianza di due IEnumerable , e tale
funzione può essere utilizzata sugli array.
La funzione SequenceEqual restituirà true se gli array hanno la stessa lunghezza ei valori negli indici
corrispondenti sono uguali e false altrimenti.
int[] arr1 = { 3, 5, 7 };
int[] arr2 = { 3, 5, 7 };
bool result = arr1.SequenceEqual(arr2);
Console.WriteLine("Arrays equal? {0}", result);
Questo stamperà:
Tutti gli array implementano l'interfaccia IList non generica (e quindi le interfacce di base
ICollection e IEnumerable non generiche).
Ancora più importante, gli array unidimensionali implementano le interfacce generiche IList<> e
IReadOnlyList<> (e le loro interfacce di base) per il tipo di dati che contengono. Ciò significa che
possono essere trattati come tipi enumerabili generici e inoltrati a una varietà di metodi senza
dover prima convertirli in un modulo non array.
int[] arr1 = { 3, 5, 7 };
IEnumerable<int> enumerableIntegers = arr1; //Allowed because arrays implement IEnumerable<T>
https://riptutorial.com/it/home 63
List<int> listOfIntegers = new List<int>();
listOfIntegers.AddRange(arr1); //You can pass in a reference to an array to populate a List.
Dopo aver eseguito questo codice, la lista listOfIntegers conterrà una List<int> contenente i
valori 3, 5 e 7.
Il supporto IEnumerable<> significa che gli array possono essere interrogati con LINQ, ad esempio
arr1.Select(i => 10 * i) .
https://riptutorial.com/it/home 64
Capitolo 11: AssemblyInfo.cs Esempi
Osservazioni
Il nome file AssemblyInfo.cs viene utilizzato per convenzione come il file di origine in cui gli
sviluppatori inseriscono attributi di metadati che descrivono l'intero assembly che stanno creando.
Examples
[AssemblyTitle]
[assembly: AssemblyTitle("MyProduct")]
[AssemblyProduct]
Questo attributo viene utilizzato per descrivere il prodotto per cui è destinato questo particolare
assieme. Più assiemi possono essere componenti dello stesso prodotto, nel qual caso possono
tutti condividere lo stesso valore per questo attributo.
[assembly: AssemblyProduct("MyProduct")]
Avere un globale consente una migliore DEUMIDITÀ, è necessario solo inserire valori diversi in
AssemblyInfo.cs per i progetti con varianza. Questo uso presuppone che il tuo prodotto abbia più
di un progetto di Visual Studio.
GlobalAssemblyInfo.cs
using System.Reflection;
using System.Runtime.InteropServices;
//using Stackoverflow domain as a made up example
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4e4f2d33-aaab-48ea-a63d-1f0a8e3c935f")]
[assembly: ComVisible(false)] //not going to expose ;)
https://riptutorial.com/it/home 65
// dynamically generate this file
// Major Version - Year 6 being 2016
// Minor Version - The month
// Day Number - Day of month
// Revision - Build number
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: [assembly: AssemblyVersion("year.month.day.*")]
[assembly: AssemblyVersion("2016.7.00.00")]
[assembly: AssemblyFileVersion("2016.7.27.3839")]
//then the following might be put into a separate Assembly file per project, e.g.
[assembly: AssemblyTitle("Stackoveflow.Redis")]
1. Seleziona Aggiungi / elemento esistente ... nel menu di scelta rapida del progetto
2. Seleziona GlobalAssemblyInfo.cs
3. Espandi il pulsante Aggiungi facendo clic su quella piccola freccia in giù sulla mano destra
4. Seleziona "Aggiungi come collegamento" nell'elenco a discesa dei pulsanti
[AssemblyVersion]
[assembly: AssemblyVersion("1.0.*")]
Il carattere * viene utilizzato per incrementare automaticamente una porzione della versione
automaticamente ogni volta che si compila (spesso utilizzato per il numero "build")
using System.Linq;
using System.Reflection;
...
Il codice nel controllo sorgente ha i numeri di versione per impostazione predefinita (ID SVN o
hash Git SHA1) o esplicitamente (tag Git). Anziché aggiornare manualmente le versioni in
https://riptutorial.com/it/home 66
AssemblyInfo.cs, è possibile utilizzare un processo di compilazione per scrivere la versione dal
sistema di controllo del codice sorgente nei file AssemblyInfo.cs e quindi negli assembly.
I pacchetti GitVersionTask o SemVer.Git.Fody NuGet sono esempi di quanto sopra. Per utilizzare
GitVersionTask, ad esempio, dopo aver installato il pacchetto nel progetto rimuovere gli attributi di
Assembly*Version dai file AssemblyInfo.cs. Questo mette GitVersionTask a capo della versione
degli assembly.
Si noti che il Semantic Versioning è sempre più lo standard di fatto , quindi questi metodi
raccomandano l'uso di tag di controllo sorgente che seguono SemVer.
Campi comuni
'AssemblyTitle' diventa la 'Descrizione file' quando si esamina la scheda Dettagli proprietà della
DLL.
[AssemblyConfiguration]
#if (DEBUG)
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
[InternalsVisibleTo]
https://riptutorial.com/it/home 67
internal da MyAssembly .
[assembly: InternalsVisibleTo("MyAssembly.UnitTests")]
Ciò è particolarmente utile per i test unitari per evitare dichiarazioni public non necessarie.
[AssemblyKeyFile]
Ogni volta che vogliamo installare il nostro assembly in GAC, è necessario avere un nome sicuro.
Per un assembly di denominazione forte, dobbiamo creare una chiave pubblica. Per generare il
file .snk .
1. Prompt dei comandi per sviluppatori per VS2015 (con accesso amministratore)
2. Al prompt dei comandi, digitare cd C: \ Directory_Name e premere INVIO.
3. Al prompt dei comandi, digitare sn -k KeyFileName.snk e quindi premere INVIO.
una volta che il file keyFileName.snk viene creato nella directory specificata, fornire refernce nel
progetto. Assegna a AssemblyKeyFileAttribute il percorso del file snk per generare la chiave quando
costruiamo la nostra libreria di classi.
[assembly: AssemblyKeyFile(@"c:\Directory_Name\KeyFileName.snk")]
Thi creerà un assembly con un nome forte dopo la build. Dopo aver creato il tuo assembly nome
sicuro, puoi installarlo in GAC
Happy Coding :)
https://riptutorial.com/it/home 68
Capitolo 12: Async-Await
introduzione
In C #, un metodo dichiarato async non bloccherà all'interno di un processo sincrono, nel caso in
cui si stiano utilizzando operazioni basate sull'I / O (ad esempio accesso Web, utilizzo di file, ...). Il
risultato di tali metodi asincroni contrassegnati può essere atteso tramite l'uso della parola chiave
await .
Osservazioni
Un metodo async può restituire void , Task o Task<T> .
Il tipo di ritorno Task attenderà che il metodo finisca e il risultato sarà void . Task<T> restituirà un
valore da tipo T dopo il completamento del metodo.
async metodi async dovrebbero restituire Task o Task<T> , in contrasto con il void , in quasi tutte le
circostanze. non è possibile await metodi async void , il che porta a una serie di problemi. L'unico
scenario in cui un async deve restituire void è nel caso di un gestore di eventi.
async / await funziona trasformando il tuo metodo async in una macchina a stati. Lo fa creando una
struttura dietro le quinte che memorizza lo stato corrente e qualsiasi contesto (come le variabili
locali) e espone un metodo MoveNext() per far avanzare gli stati (ed eseguire qualsiasi codice
associato) ogni volta che un attendibile atteso si completa.
Examples
Semplici chiamate consecutive
La cosa principale da notare qui è che mentre ogni await metodo -ed è chiamato in modo
asincrono - e per il tempo di quella chiamata il controllo viene ceduto al sistema - il flusso
all'interno del metodo è lineare e non richiede alcun trattamento speciale a causa di asincronia. Se
uno dei metodi chiamati fallisce, l'eccezione verrà elaborata "come previsto", che in questo caso
significa che l'esecuzione del metodo verrà interrotta e l'eccezione salirà nello stack.
6.0
https://riptutorial.com/it/home 69
A partire da C # 6.0, la parola chiave await ora può essere utilizzata all'interno di un blocco catch e
finally .
try {
var client = new AsyncClient();
await client.DoSomething();
} catch (MyException ex) {
await client.LogExceptionAsync();
throw;
} finally {
await client.CloseAsync();
}
5.0 6.0
Prima di C # 6.0, avresti bisogno di fare qualcosa sulla falsariga di quanto segue. Si noti che 6.0
ha anche ripulito i controlli null con l' operatore Null Propagating .
AsynClient client;
MyException caughtException;
try {
client = new AsyncClient();
await client.DoSomething();
} catch (MyException ex) {
caughtException = ex;
}
if (client != null) {
if (caughtException != null) {
await client.LogExceptionAsync();
}
await client.CloseAsync();
if (caughtException != null) throw caughtException;
}
Si noti che se si attende un'attività non creata da async (ad esempio un'attività creata da Task.Run ),
alcuni debugger potrebbero interrompersi sulle eccezioni generate dall'attività anche se
apparentemente gestite dal try / catch circostante. Questo accade perché il debugger lo considera
non gestito rispetto al codice utente. In Visual Studio, c'è un'opzione chiamata "Just My Code" ,
che può essere disattivata per impedire che il debugger si rompa in tali situazioni.
Il web.config system.web.httpRuntime deve targetizzare 4.5 per garantire che il thread affitterà il
contesto della richiesta prima di riprendere il metodo asincrono.
Async e attendere hanno un comportamento indefinito su ASP.NET precedente alla 4.5. Async /
await riprenderà su un thread arbitrario che potrebbe non avere il contesto della richiesta. Le
applicazioni sotto carico falliranno casualmente con eccezioni di riferimento null accedendo a
https://riptutorial.com/it/home 70
HttpContext dopo l'attesa. L'utilizzo di HttpContext.Current in WebApi è pericoloso a causa di
async
Chiamate contemporanee
await firstTask;
await secondTask;
}
In alternativa, Task.WhenAll può essere utilizzato per raggruppare più attività in una singola Task ,
che viene completata quando tutte le attività passate sono complete.
await Task.WhenAll(tasks);
Per ottenere risultati da un'attività dopo aver atteso più attività con Task.WhenAll, è sufficiente
attendere di nuovo l'attività. Poiché l'attività è già completata, verrà restituito il risultato
Inoltre, Task.WhenAny può essere utilizzato per eseguire più attività in parallelo, come Task.WhenAll
sopra, con la differenza che questo metodo verrà completato quando verrà completata una delle
attività fornite.
https://riptutorial.com/it/home 71
public async Task RunConcurrentTasksWhenAny()
{
var firstTask = TaskOperation("#firstTask executed");
var secondTask = TaskOperation("#secondTask executed");
var thirdTask = TaskOperation("#thirdTask executed");
await Task.WhenAny(firstTask, secondTask, thirdTask);
}
L' Task restituita da RunConcurrentTasksWhenAny verrà completata quando una delle operazioni
firstTask , secondTask o thirdTask completata.
Il metodo asincrono in cui viene utilizzata l' attesa deve essere modificato dalla parola
chiave async .
L'opposto non è sempre vero: puoi contrassegnare un metodo come async senza utilizzare l' await
nel suo corpo.
Ciò che in realtà await è sospendere l'esecuzione del codice fino al completamento dell'attività
atteso; qualsiasi attività può essere attesa.
Nota: non è possibile attendere il metodo asincrono che non restituisce nulla (nulla).
diventa:
https://riptutorial.com/it/home 72
{
// ...
}
Qualsiasi metodo usuale può essere trasformato in asincrono nel seguente modo:
Ciò può essere vantaggioso quando è necessario eseguire un metodo a esecuzione prolungata
sul thread dell'interfaccia utente senza bloccare l'interfaccia utente.
Ma c'è un'osservazione molto importante qui: Asincrono non significa sempre concomitante
(parallelo o addirittura multi-thread). Anche su un singolo thread, async - await consente ancora
il codice asincrono. Ad esempio, vedere questo Utilità di pianificazione personalizzata. Un
programmatore di compiti così "pazzo" può semplicemente trasformare compiti in funzioni
chiamate all'interno dell'elaborazione del loop di messaggi.
Dobbiamo chiederci: quale thread eseguirà la continuazione del nostro metodo DoIt_Continuation
?
Per impostazione predefinita, l'operatore di await pianifica l'esecuzione della continuazione con il
contesto di sincronizzazione corrente. Significa che per impostazione predefinita per le sequenze
di esecuzione WinForms e WPF nel thread dell'interfaccia utente. Se, per qualche motivo, è
necessario modificare questo comportamento, utilizzare il metodo Task.ConfigureAwait() :
I metodi che eseguono operazioni asincrone non devono essere utilizzati await se:
https://riptutorial.com/it/home 73
var lookupKey = "Users" + id;
return dataStore.GetByKeyAsync(lookupKey);
}
In questo caso, il metodo non deve essere contrassegnato come async , anche se sta
preformando un'operazione asincrona. L'attività restituita da GetByKeyAsync viene passata
direttamente al metodo chiamante, dove sarà await ed.
Ciò migliorerà le prestazioni poiché salverà il compilatore la generazione di una macchina di stato
asincrono extra.
È una cattiva pratica bloccare le chiamate asincrone poiché può causare deadlock in ambienti con
un contesto di sincronizzazione. La migliore pratica è usare async / attendere "fino in fondo". Ad
esempio, il seguente codice Windows Form causa un deadlock:
https://riptutorial.com/it/home 74
return true;
}
Nota: i gestori di eventi sono l'unico posto in cui dovrebbe essere usato il async void (perché non è
possibile attendere un metodo di async void ).
https://riptutorial.com/it/home 75
{
MethodB();
// Do other work
}
https://riptutorial.com/it/home 76
Capitolo 13: attributi
Examples
Creare un attributo personalizzato
Utilizzando un attributo
Leggere un attributo
https://riptutorial.com/it/home 77
foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
Console.WriteLine(attribute.GetType());
}
GetCustomAttribute ha anche una firma generica per specificare il tipo di attributo da cercare.
L'argomento Boolean inherit può essere passato ad entrambi questi metodi. Se questo valore è
impostato su true gli antenati dell'elemento dovrebbero essere esaminati.
DebuggerDisplay Attribute
Le espressioni racchiuse in {} verranno valutate dal debugger. Può trattarsi di una proprietà
semplice come nell'esempio seguente o in una logica più complessa.
[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
Aggiungendo ,nq prima della parentesi di chiusura rimuove le virgolette quando si stampa una
stringa.
[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]
https://riptutorial.com/it/home 78
non vengono verificate per la validità. Quindi un attributo DebuggerDisplay contenente una logica
più complessa di una semplice aritmetica potrebbe funzionare bene in C #, ma la stessa
espressione valutata in VB.NET probabilmente non sarà sintatticamente valida e produrrà un
errore durante il debug.
Un modo per rendere DebuggerDisplay più indipendente dalla lingua è scrivere l'espressione in un
metodo o in una proprietà e chiamarla invece.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
Si potrebbe desiderare che DebuggerDisplay restituisca tutte o solo alcune proprietà e durante il
debug e l'ispezione del tipo dell'oggetto.
L'esempio seguente circonda anche il metodo helper con #if DEBUG dato che DebuggerDisplay viene
utilizzato negli ambienti di debug.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
#if DEBUG
private string DebuggerDisplay()
{
return
$"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty},
Type:{this.GetType()}";
}
#endif
}
Gli attributi di informazioni sul chiamante possono essere utilizzati per trasmettere informazioni
sull'invocatore al metodo richiamato. La dichiarazione assomiglia a questo:
using System.Runtime.CompilerServices;
https://riptutorial.com/it/home 79
{
//perform logging
}
Si noti che solo il primo parametro viene passato esplicitamente al metodo LogException mentre il
resto di essi verrà fornito in fase di compilazione con i valori pertinenti.
E il parametro 'callerFilePath' riceverà il percorso completo del file in cui è stato dichiarato il
metodo Save .
Non esiste un modo semplice per ottenere attributi da un'interfaccia, poiché le classi non
ereditano gli attributi da un'interfaccia. Ogni volta che si implementa un'interfaccia o si
sovrascrivono i membri in una classe derivata, è necessario dichiarare nuovamente gli attributi.
Quindi nell'esempio seguente l'output sarebbe True in tutti e tre i casi.
using System;
using System.Linq;
using System.Reflection;
namespace InterfaceAttributesDemo {
https://riptutorial.com/it/home 80
}
var attribute2 =
typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
Console.WriteLine(attribute2 == null); // True
Un modo per recuperare gli attributi dell'interfaccia è cercarli attraverso tutte le interfacce
implementate da una classe.
Attributo obsoleto
System.Obsolete è un attributo che viene utilizzato per contrassegnare un tipo o un membro che
ha una versione migliore e pertanto non deve essere utilizzato.
Nel caso in cui la classe sopra sia usata, il compilatore darà l'avvertimento "Questa classe è
obsoleta. Usa SomeOtherClass invece."
https://riptutorial.com/it/home 81
Capitolo 14: BackgroundWorker
Sintassi
• bgWorker.CancellationPending //returns whether the bgWorker was cancelled during its
operation
Osservazioni
L'esecuzione di operazioni a esecuzione prolungata all'interno del thread dell'interfaccia utente
può causare la mancata risposta dell'applicazione, visualizzando all'utente che ha smesso di
funzionare. È preferibile che queste attività vengano eseguite su un thread in background. Una
volta completata, l'interfaccia utente può essere aggiornata.
In genere, BackgroundWorker viene utilizzato solo nelle applicazioni Windows Form. Nelle
applicazioni WPF, le attività vengono utilizzate per scaricare il lavoro sui thread in background
(eventualmente in combinazione con async / await ). Gli aggiornamenti di marshalling sul thread
dell'interfaccia utente vengono in genere eseguiti automaticamente, quando la proprietà da
aggiornare implementa INotifyPropertyChanged o manualmente utilizzando il Dispatcher del
thread dell'interfaccia utente.
Examples
Assegnazione di gestori di eventi a un BackgroundWorker
bgWorker.DoWork += bgWorker_DoWork;
https://riptutorial.com/it/home 82
/*This is how the DoWork event method signature looks like:*/
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Work to be done here
// ...
// To get a reference to the current Backgroundworker:
BackgroundWorker worker = sender as BackgroundWorker;
// The reference to the BackgroundWorker is often used to report progress
worker.ReportProgress(...);
}
/*This is the method that will be run once the BackgroundWorker has completed its tasks */
bgWorker.RunWorkerCompleted += bgWorker_CompletedWork;
bgWorker.ProgressChanged += bgWorker_ProgressChanged;
bgWorker.WorkerSupportsCancellation = true;
Ciò consente al lavoratore di segnalare lo stato di avanzamento tra il completamento delle attività
...
bgWorker.WorkerReportsProgress = true;
https://riptutorial.com/it/home 83
tempo, senza bloccare il thread dell'interfaccia utente.
namespace BGWorkerExample
{
public partial class ExampleForm : Form
{
namespace BgWorkerExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
prgProgressBar.Step = 1;
//tell the backgroundWorker to raise the "DoWork" event, thus starting it.
//Check to make sure the background worker is not already running.
if(!bgWorker.IsBusy)
bgWorker.RunWorkerAsync();
https://riptutorial.com/it/home 84
private void bgWorker_WorkComplete(object sender, RunWorkerCompletedEventArgs e)
{
//e.Error will contain any exceptions caught by the backgroundWorker
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else
{
MessageBox.Show("Task Complete!");
prgProgressBar.Value = 0;
}
}
https://riptutorial.com/it/home 85
Capitolo 15: BigInteger
Osservazioni
Quando usare
oggetti BigInteger sono per loro natura molto pesanti sulla RAM. Di conseguenza,
BigInteger
dovrebbero essere usati solo quando assolutamente necessario, cioè per numeri su scala
veramente astronomica.
Oltre a ciò, tutte le operazioni aritmetiche su questi oggetti sono di un ordine di grandezza più
lento delle loro controparti primitive, questo problema viene ulteriormente aggravato man mano
che il numero cresce man mano che non sono di dimensioni fisse. È quindi possibile che un
BigInteger possa causare un arresto anomalo consumando tutta la RAM disponibile.
alternative
Se la velocità è imperativa per la soluzione, potrebbe essere più efficiente implementare questa
funzionalità da soli utilizzando una classe che include un Byte[] e sovraccaricando gli operatori
necessari da soli. Tuttavia, questo richiede un notevole sforzo extra.
Examples
Calcola il primo numero di Fibonacci a 1.000 cifre
using System;
using System.Numerics;
namespace Euler_25
{
class Program
{
static void Main(string[] args)
{
BigInteger l1 = 1;
BigInteger l2 = 1;
BigInteger current = l1 + l2;
while (current.ToString().Length < 1000)
{
l2 = l1;
l1 = current;
current = l1 + l2;
}
Console.WriteLine(current);
}
}
}
https://riptutorial.com/it/home 86
Questo semplice algoritmo esegue l'iterazione dei numeri di Fibonacci fino a raggiungere una cifra
di almeno 1000 cifre decimali, quindi lo stampa. Questo valore è significativamente più grande di
ulong potrebbe mantenere un ulong .
Teoricamente, l'unico limite della classe BigInteger è la quantità di RAM che l'applicazione può
consumare.
https://riptutorial.com/it/home 87
Capitolo 16: BindingList
Examples
Evitando l'iterazione N * 2
Ciò richiede molto tempo per eseguire, per risolvere, fare quanto segue:
https://riptutorial.com/it/home 88
Capitolo 17: C # 3.0 Caratteristiche
Osservazioni
La versione 3.0 di C # è stata rilasciata come parte di .Net versione 3.5. Molte delle funzionalità
aggiunte con questa versione erano a supporto di LINQ (Language Integrated Queries).
• LINQ
• Espressioni Lambda
• Metodi di estensione
• Tipi anonimi
• Variabili implicitamente tipizzate
• Inizializzatori di oggetti e collezioni
• Proprietà implementate automaticamente
• Alberi espressione
Examples
Variabili implicitamente tipizzate (var)
La parola chiave var consente a un programmatore di digitare implicitamente una variabile in fase
di compilazione. var dichiarazioni var hanno lo stesso tipo di variabili dichiarate esplicitamente.
I tipi delle variabili precedenti sono rispettivamente int , double , StringBuilder e un tipo anonimo.
È importante notare che una variabile var non viene digitata in modo dinamico. SquaredNumber =
Builder non è valido poiché stai provando a impostare int su un'istanza di StringBuilder
//Example 1
int[] array = { 1, 5, 2, 10, 7 };
// Select squares of all odd numbers in the array sorted in descending order
IEnumerable<int> query = from x in array
where x % 2 == 1
https://riptutorial.com/it/home 89
orderby x descending
select x * x;
// Result: 49, 25, 1
L'esempio 1 utilizza la sintassi della query che è stata progettata per sembrare simile alle query
SQL.
//Example 2
IEnumerable<int> query = array.Where(x => x % 2 == 1)
.OrderByDescending(x => x)
.Select(x => x * x);
// Result: 49, 25, 1 using 'array' as defined in previous example
L'esempio 2 utilizza la sintassi del metodo per ottenere lo stesso risultato dell'esempio 1.
È importante notare che, in C #, la sintassi della query LINQ è zucchero sintattico per la sintassi
del metodo LINQ. Il compilatore traduce le query in chiamate di metodo in fase di compilazione.
Alcune query devono essere espresse nella sintassi del metodo. Da MSDN : "Ad esempio, è
necessario utilizzare una chiamata al metodo per esprimere una query che recupera il numero di
elementi che corrispondono a una condizione specificata."
Espressioni Lambda
using System;
using System.Collections.Generic;
using System.Linq;
Il codice sopra mostrerà la somma dei quadrati dei numeri da 1 a 10 alla console.
La prima espressione lambda quadra i numeri nella lista. Poiché esiste solo una parentesi sui
parametri, può essere omessa. Puoi includere le parentesi se lo desideri:
https://riptutorial.com/it/home 90
o digitare esplicitamente il parametro, ma sono necessarie le parentesi:
Il corpo lambda è un'espressione e ha un ritorno implicito. Puoi usare un corpo di statement anche
se lo desideri. Questo è utile per lambda più complessi.
La seconda espressione lambda somma i numeri nell'elenco restituito dal metodo select. Le
parentesi sono obbligatorie in quanto vi sono più parametri. I tipi dei parametri sono digitati in
modo esplicito ma non è necessario. Il metodo seguente è equivalente.
Come è questo:
Tipi anonimi
I tipi anonimi forniscono un modo conveniente per incapsulare un insieme di proprietà di sola
lettura in un singolo oggetto senza dover prima definire esplicitamente un tipo. Il nome del tipo è
generato dal compilatore e non è disponibile a livello di codice sorgente. Il tipo di ogni proprietà è
dedotto dal compilatore.
È possibile creare tipi anonimi utilizzando la new parola chiave seguita da una parentesi graffa ( { )
. All'interno delle parentesi graffe, è possibile definire proprietà come nel codice sottostante.
È anche possibile creare una serie di tipi anonimi. Vedi il codice qui sotto:
var a = new[] {
new {
Fruit = "Apple",
Color = "Red"
},
new {
Fruit = "Banana",
Color = "Yellow"
}
};
https://riptutorial.com/it/home 91
select new { prod.Color, prod.Price };
https://riptutorial.com/it/home 92
Capitolo 18: C # 4.0 Caratteristiche
Examples
Parametri opzionali e argomenti con nome
1. Espressione costante
2. Deve essere un tipo di valore come enum o struct.
3. Deve essere un'espressione di default del modulo (valueType)
public void ExampleMethod(int required, string optValue = "test", int optNum = 42)
{
//...
}
Consente di passare l'argomento alla funzione associando il nome del parametro Non è
necessario per ricordare la posizione dei parametri che non siamo a conoscenza di sempre. Non
c'è bisogno di guardare l'ordine dei parametri nella lista dei parametri della funzione chiamata.
Possiamo specificare il parametro per ogni argomento in base al suo nome.
La specifica dell'argomento con nome deve apparire dopo che sono stati specificati tutti gli
argomenti fissi.
Se si usa un argomento con nome prima di un argomento fisso, si otterrà un errore in fase di
compilazione come segue.
https://riptutorial.com/it/home 93
La specifica dell'argomento con nome deve apparire dopo che sono stati specificati tutti gli
argomenti fissi
Varianza
Interfacce e delegati generici possono avere i loro parametri di tipo contrassegnati come covarianti
o controvarianti usando rispettivamente le parole chiave out e in . Queste dichiarazioni vengono
quindi rispettate per le conversioni di tipo, sia implicite che esplicite, e compilano sia il tempo che il
tempo di esecuzione.
La parola chiave ref per i chiamanti di metodi è ora facoltativa quando si chiama nei metodi forniti
dalle interfacce COM. Dato un metodo COM con la firma
Una nuova dynamic pseudo-tipo viene introdotta nel sistema di tipo C #. Viene trattato come
System.Object , ma in aggiunta, qualsiasi accesso membro (chiamata di metodo, campo, proprietà
https://riptutorial.com/it/home 94
o accesso dell'indicizzatore o invocazione di un delegato) o applicazione di un operatore su un
valore di tale tipo è consentito senza alcun tipo di controllo, e la sua risoluzione è posticipata fino
al momento dell'esecuzione. Questo è noto come digitazione anatra o rilegatura tardiva. Per
esempio:
In questo caso, viene utilizzato il tipo dinamico per evitare riflessioni più dettagliate. Usa ancora
Reflection sotto il cofano, ma di solito è più veloce grazie al caching.
Il tipo dinamico ha applicazioni anche nel codice per lo più tipizzato staticamente, per esempio
rende possibile la doppia spedizione senza implementare il pattern Visitor.
https://riptutorial.com/it/home 95
Capitolo 19: C # 5.0 Caratteristiche
Sintassi
• Async e attesa
Parametri
Osservazioni
C # 5.0 è abbinato a Visual Studio .NET 2012
Examples
Async e attesa
https://riptutorial.com/it/home 96
async e await sono due operatori che hanno lo scopo di migliorare le prestazioni liberando Thread
e attendendo il completamento delle operazioni prima di andare avanti.
Ecco un esempio di come ottenere una stringa prima di restituire la sua lunghezza:
Ecco un altro esempio di download di un file e gestione di ciò che accade quando il progresso è
cambiato e al termine del download (ci sono due modi per farlo):
Metodo 1:
//This one using async event handlers, but not async coupled with await
private void DownloadAndUpdateAsync(string uri, string DownloadLocation){
WebClient web = new WebClient();
//Assign the event handler
web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
web.DownloadFileCompleted += new AsyncCompletedEventHandler(FileCompleted);
//Download the file asynchronously
web.DownloadFileAsync(new Uri(uri), DownloadLocation);
}
Metodo 2:
https://riptutorial.com/it/home 97
//Assign the event handler
web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
//Download the file async
web.DownloadFileAsync(new Uri(uri), DownloadLocation);
//Notice how there is no complete event, instead we're using techniques from the first
example
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e){
int i = 0;
i++;
doSomething();
}
private void doProcess(){
//Wait for the download to finish
await DownloadAndUpdateAsync(new Uri("http://example.com/file"))
doSomething();
}
Le CIA sono intese come un modo semplice per ottenere attributi da qualunque cosa stia
chiamando il metodo mirato. C'è solo un modo per usarli e ci sono solo 3 attributi.
Esempio:
//This is the "calling method": the method that is calling the target method
public void doProcess()
{
GetMessageCallerAttributes("Show my attributes.");
}
//This is the target method
//There are only 3 caller attributes
public void GetMessageCallerAttributes(string message,
//gets the name of what is calling this method
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
//gets the path of the file in which the "calling method" is in
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
//gets the line number of the "calling method"
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
//Writes lines of all the attributes
System.Diagnostics.Trace.WriteLine("Message: " + message);
System.Diagnostics.Trace.WriteLine("Member: " + memberName);
System.Diagnostics.Trace.WriteLine("Source File Path: " + sourceFilePath);
System.Diagnostics.Trace.WriteLine("Line Number: " + sourceLineNumber);
}
Esempio di output:
https://riptutorial.com/it/home 98
Capitolo 20: C # 6.0 Caratteristiche
introduzione
Questa sesta iterazione del linguaggio C # è fornita dal compilatore di Roslyn. Questo compilatore
è uscito con la versione 4.6 di .NET Framework, tuttavia può generare codice in un modo
compatibile con le versioni precedenti per consentire il targeting di versioni precedenti del
framework. Il codice di versione 6 C # può essere compilato in modo completamente retroattivo
con .NET 4.0. Può anche essere utilizzato per i framework precedenti, tuttavia alcune funzionalità
che richiedono supporto framework aggiuntivo potrebbero non funzionare correttamente.
Osservazioni
La sesta versione di C # è stata rilasciata a luglio 2015 insieme a Visual Studio 2015 e .NET 4.6.
Oltre ad aggiungere alcune nuove funzionalità linguistiche include una completa riscrittura del
compilatore. Precedentemente csc.exe era un'applicazione nativa di Win32 scritta in C ++, con C #
6 ora è un'applicazione gestita .NET scritta in C #. Questa riscrittura era conosciuta come progetto
"Roslyn" e il codice è ora open source e disponibile su GitHub .
Examples
Nome dell'operatore
L'operatore nameof restituisce il nome di un elemento di codice come una string . Ciò è utile
quando si INotifyPropertyChanged eccezioni relative agli argomenti del metodo e anche quando si
implementa INotifyPropertyChanged .
L'operatore nameof viene valutato al momento della compilazione e modifica l'espressione in una
stringa letterale. Questo è utile anche per le stringhe che prendono il nome dal loro membro che le
espone. Considera quanto segue:
https://riptutorial.com/it/home 99
Dal nameof espressioni nameof sono costanti in fase di compilazione, possono essere utilizzate in
attributi, etichette case , istruzioni switch e così via.
Console.WriteLine(Enum.One.ToString());
è possibile usare:
Console.WriteLine(nameof(Enum.One))
L'operatore nameof può accedere ai membri non statici usando la sintassi di tipo statico. Invece di
fare:
L'output sarà Length in entrambi gli esempi. Tuttavia, quest'ultimo impedisce la creazione di
istanze non necessarie.
Sebbene l'operatore nameof con la maggior parte dei costrutti di linguaggio, esistono alcune
limitazioni. Ad esempio, non è possibile utilizzare l'operatore nameof tipi generici aperti o valori
restituiti dal metodo:
Console.WriteLine(nameof(List<int>)); // "List"
Console.WriteLine(nameof(List<bool>)); // "List"
6.0
Espressione:
Uso:
Si noti che questo approccio determina la creazione di un albero di espressioni per ogni chiamata,
quindi le prestazioni sono molto peggiori rispetto all'operatore nameof che viene valutato in fase di
compilazione e che non ha sovraccarico in fase di esecuzione.
I membri delle funzioni con corpo espressivo consentono l'uso di espressioni lambda come corpi
membri. Per i membri semplici, può risultare in un codice più pulito e più leggibile.
Le funzioni con corpo espressivo possono essere utilizzate per proprietà, indicizzatori, metodi e
operatori.
Proprietà
public decimal TotalPrice => BasePrice + Taxes;
È equivalente a:
https://riptutorial.com/it/home 101
{
return BasePrice + Taxes;
}
}
Quando una funzione con un'espressione viene utilizzata con una proprietà, la proprietà viene
implementata come proprietà di solo getter.
Visualizza la demo
indicizzatori
public object this[string key] => dictionary[key];
È equivalente a:
metodi
static int Multiply(int a, int b) => a * b;
È equivalente a:
https://riptutorial.com/it/home 102
public class Foo
{
public int Bar { get; }
operatori
Questo può anche essere utilizzato dagli operatori:
limitazioni
I membri delle funzioni con corpo di espressione hanno alcune limitazioni. Non possono contenere
istruzioni di blocco e qualsiasi altra istruzione che contenga blocchi: if , switch , for , foreach ,
while , do , try , etc.
Alcuni if dichiarazioni possono essere sostituite con operatori ternari. Alcune istruzioni for e
foreach possono essere convertite in query LINQ, ad esempio:
IEnumerable<string> Digits
{
get
{
for (int i = 0; i < 10; i++)
yield return i.ToString();
}
}
In tutti gli altri casi, è possibile utilizzare la vecchia sintassi per i membri delle funzioni.
I membri delle funzioni con corpo di espressione possono contenere async / await , ma spesso
sono ridondanti:
https://riptutorial.com/it/home 103
Task<int> Foo() => Bar();
Filtri di eccezione
I filtri di eccezione offrono agli sviluppatori la possibilità di aggiungere una condizione (sotto forma
di espressione boolean ) a un blocco catch , consentendo l'esecuzione del catch solo se la
condizione è true .
I filtri di eccezione sono stati supportati dal CLR sin dall'inizio e sono stati accessibili
da VB.NET e F # per oltre un decennio esponendo una parte del modello di gestione
delle eccezioni CLR. Solo dopo il rilascio di C # 6.0 la funzionalità è stata disponibile
anche per gli sviluppatori C #.
È possibile combinare più blocchi catch con clausole when . Il primo when clausola che restituisce
true causerà l'intercettazione dell'eccezione. Il suo blocco di catch verrà inserito, mentre le altre
clausole di catch verranno ignorate (le loro clausole when non saranno valutate). Per esempio:
try
{ ... }
catch (Exception ex) when (someCondition) //If someCondition evaluates to true,
//the rest of the catches are ignored.
{ ... }
catch (NotImplementedException ex) when (someMethod()) //someMethod() will only run if
//someCondition evaluates to false
https://riptutorial.com/it/home 104
{ ... }
catch(Exception ex) // If both when clauses evaluate to false
{ ... }
Può essere rischioso utilizzare filtri di eccezione: quando l' Exception viene lanciata
dall'interno del when la clausola, l' Exception dal when clausola viene ignorato e viene
trattato come false . Questo approccio consente agli sviluppatori di scrivere when
clausola senza occuparsi di casi non validi.
Visualizza la demo
Si noti che i filtri delle eccezioni evitano i problemi con il numero di riga confusi associati all'uso di
throw quando il codice fallito si trova all'interno della stessa funzione. Ad esempio in questo caso il
numero di riga è riportato come 6 anziché 3:
1. int a = 0, b = 0;
2. try {
3. int c = a / b;
4. }
5. catch (DivideByZeroException) {
6. throw;
7. }
https://riptutorial.com/it/home 105
Il numero di riga di eccezione è segnalato come 6 perché l'errore è stato rilevato e ri-generato con
l'istruzione throw sulla riga 6.
1. int a = 0, b = 0;
2. try {
3. int c = a / b;
4. }
5. catch (DivideByZeroException) when (a != 0) {
6. throw;
7. }
In questo esempio a è 0 quindi la clausola catch viene ignorata ma 3 viene riportato come numero
di riga. Questo perché non si srotolano lo stack . Più specificamente, l'eccezione non viene
rilevata sulla linea 5 perché a infatti fa uguale 0 e quindi non v'è alcuna possibilità per l'eccezione
di essere ri-gettato sulla linea 6 perché la linea 6 non viene eseguito.
Tieni presente che sebbene questo sembra essere un modo comodo di registrazione,
può essere rischioso, specialmente se vengono utilizzati assembly di logging di terze
parti. Questi potrebbero generare eccezioni durante l'accesso a situazioni non ovvie
che potrebbero non essere rilevate facilmente (vedere Risky when(...) clausola
precedente).
try
{
DoSomethingThatMightFail(s);
}
catch (Exception ex) when (Log(ex, "An error occurred"))
{
// This catch block will never be reached
}
// ...
Visualizza la demo
https://riptutorial.com/it/home 106
6.0
try
{
DoSomethingThatMightFail(s);
}
catch (Exception ex)
{
Log(ex, "An error occurred");
throw;
}
// ...
Visualizza la demo
Il blocco finally
Il blocco finally viene eseguito ogni volta che l'eccezione viene lanciata o meno. Una sottigliezza
con le espressioni in when filtri delle eccezioni vengono eseguiti più in alto nello stack prima di
entrare nei blocchi finally interni. Ciò può causare risultati e comportamenti imprevisti quando il
codice tenta di modificare lo stato globale (come l'utente o la cultura del thread corrente) e
reimpostarlo in un blocco finally .
https://riptutorial.com/it/home 107
}
Uscita prodotta:
Inizio
Valutazioni: True
Infine interiore
Catturare
Finalmente esterno
Visualizza la demo
È anche comune vedere classi di helper IDisposable sfruttano la semantica dell'utilizzo di blocchi
per raggiungere lo stesso obiettivo, poiché IDisposable.Dispose verrà sempre chiamato prima che
un'eccezione chiamata all'interno di un blocco using inizi a scoppiare nello stack.
https://riptutorial.com/it/home 108
introduzione
Le proprietà possono essere inizializzate con l'operatore = dopo la chiusura } . La classe
Coordinate seguito mostra le opzioni disponibili per inizializzare una proprietà:
6.0
Questo esempio mostra anche come inizializzare una proprietà con un tipo complesso. Inoltre, le
proprietà automatiche non possono essere solo di scrittura, quindi preclude anche
l'inizializzazione di sola scrittura.
6.0
https://riptutorial.com/it/home 109
public class Coordinate
{
private int _x = 34;
public int X { get { return _x; } set { _x = value; } }
public Coordinate()
{
_z = 42;
}
}
Visualizza la demo
uso
Gli inizializzatori devono valutare le espressioni statiche, proprio come gli inizializzatori di campo.
Se è necessario fare riferimento a membri non statici, è possibile inizializzare le proprietà in
costruttori come in precedenza oppure utilizzare proprietà con corpo di espressione. Le
espressioni non statiche, come quella seguente (commentate), generano un errore del
compilatore:
Questo metodo può essere applicato anche a proprietà con diversi livelli di accesso:
https://riptutorial.com/it/home 110
public short Type { get; private set; } = 15;
Visualizza la demo
Note cautelative
Fai attenzione a non confondere gli inizializzatori di auto-proprietà o di campo con metodi di
espressione del corpo simili che utilizzano => anziché = , e campi che non includono { get; } .
Manca { get; } nella dichiarazione della proprietà risulta in un campo pubblico. Sia gli utenti di
proprietà di Users1 lettura Users1 che quelli di lettura-scrittura Users2 vengono inizializzati solo una
volta, ma un campo pubblico consente di modificare l'istanza di raccolta dall'esterno della classe,
che di solito non è desiderabile. La modifica di una proprietà automatica di sola lettura con il corpo
di un'espressione in proprietà di sola lettura con l'inizializzatore richiede non solo la rimozione di >
da => , ma l'aggiunta di { get; } .
Il diverso simbolo ( => invece di = ) in Users3 risulta in ogni accesso alla proprietà che restituisce
una nuova istanza di HashSet<UserDto> che, mentre C # valido (dal punto di vista del compilatore) è
improbabile che sia il comportamento desiderato quando usato per un membro della collezione.
https://riptutorial.com/it/home 111
Il codice sopra è equivalente a:
Inizializzatori dell'indice
Qualsiasi oggetto che abbia un getter o setter indicizzato può essere usato con questa sintassi:
class Program
{
public class MyClassWithIndexer
{
public int this[string index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
}
Console.ReadKey();
}
https://riptutorial.com/it/home 112
}
Produzione:
Visualizza la demo
class Program
{
public class MyClassWithIndexer
{
public int this[string index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
public string this[int index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
}
Produzione:
Va notato che l'accessore del set dell'indicizzatore potrebbe comportarsi in modo diverso rispetto
a un metodo Add (utilizzato negli inizializzatori della raccolta).
Per esempio:
https://riptutorial.com/it/home 113
var d = new Dictionary<string, int>
{
["foo"] = 34,
["foo"] = 42,
}; // does not throw, second value overwrites the first one
contro:
Interpolazione a stringa
L'interpolazione delle stringhe consente allo sviluppatore di combinare variables e testo per
formare una stringa.
Esempio di base
Vengono create due variabili int : foo e bar .
Console.WriteLine(resultString);
Uscita :
Visualizza la demo
Le bretelle all'interno delle stringhe possono ancora essere utilizzate, come questa:
https://riptutorial.com/it/home 114
Utilizzo dell'interpolazione con letterali
stringa letterali
Usando @ prima della stringa, la stringa verrà interpretata letteralmente. Quindi, ad esempio, i
caratteri Unicode o le interruzioni di riga rimarranno esattamente come sono stati digitati. Tuttavia,
questo non influirà sulle espressioni in una stringa interpolata come mostrato nell'esempio
seguente:
Produzione:
Visualizza la demo
espressioni
Con l'interpolazione delle stringhe, è possibile valutare anche le espressioni all'interno di parentesi
graffe {} . Il risultato verrà inserito nella posizione corrispondente all'interno della stringa. Ad
esempio, per calcolare il massimo di foo e bar e inserirlo, utilizzare Math.Max tra parentesi graffe:
Produzione:
E il più grande è: 42
Nota: tutti gli spazi bianchi iniziali o finali (inclusi spazio, scheda e CRLF / nuova riga) tra la
parentesi graffa e l'espressione vengono completamente ignorati e non inclusi nell'output
Visualizza la demo
https://riptutorial.com/it/home 115
Console.WriteLine($"Foo formatted as a currency to 4 decimal places: {foo:c4}");
Produzione:
Visualizza la demo
Produzione:
Visualizza la demo
Console.WriteLine($"{(foo > bar ? "Foo is larger than bar!" : "Bar is larger than foo!")}");
Produzione:
Visualizza la demo
Produzione:
Sequenze di fuga
L'escape dei caratteri barra rovesciata ( \ ) e virgola ( " ) funziona esattamente nello stesso modo
nelle stringhe interpolate come nelle stringhe non interpolate, sia per i letterali stringa letterale che
per quelli non verbali:
Console.WriteLine($"Foo is: {foo}. In a non-verbatim string, we need to escape \" and \\ with
backslashes.");
Console.WriteLine($@"Foo is: {foo}. In a verbatim string, we need to escape "" with an extra
https://riptutorial.com/it/home 116
quote, but we don't need to escape \");
Produzione:
Foo è 34. In una stringa non-letterale, dobbiamo uscire da "e \ con barre retroverse.
Foo è 34. In una stringa letterale, dobbiamo scappare "con una citazione extra, ma non
abbiamo bisogno di scappare \
Per includere una parentesi graffa { o } in una stringa interpolata, utilizzare due parentesi graffe {{
o }} :
Produzione:
{foo} è: 34
Visualizza la demo
FormattableString type
Il tipo di $"..." espressione di interpolazione della stringa non è sempre una stringa semplice. Il
compilatore decide quale tipo assegnare a seconda del contesto:
Questo è anche l'ordine delle preferenze di tipo quando il compilatore deve scegliere quale
metodo di overload verrà chiamato.
// ...
}
https://riptutorial.com/it/home 117
Chiama il metodo sopra con:
Ad esempio, si potrebbe scegliere di non sostenere il costo delle prestazioni della formattazione
della stringa se il livello di registrazione stava già filtrando l'elemento del registro.
Conversioni implicite
Esistono conversioni di tipo implicite da una stringa interpolata:
Puoi anche produrre una variabile IFormattable che ti permette di convertire la stringa con un
contesto invariante:
Quindi, per produrre una stringa corretta per la cultura corrente, basta usare l'espressione:
Nota : Current e Invariant non possono essere creati come metodi di estensione perché, per
impostazione predefinita, il compilatore assegna il tipo String all'espressione di stringa interpolata
che non riesce a compilare il seguente codice:
https://riptutorial.com/it/home 118
FormattableStringclasse FormattableString contiene già il metodo Invariant() , quindi il modo più
semplice per passare alla cultura invariante è affidarsi using static :
Dietro le quinte
Le stringhe interpolate sono solo uno zucchero sintattico per String.Format() . Il compilatore (
Roslyn ) lo trasformerà in un String.Format dietro le quinte:
// ...
https://riptutorial.com/it/home 119
Logger.Log(string.Format(ErrorFormat, ex));
Le stringhe interpolate, tuttavia, non verranno compilate con i segnaposto che fanno riferimento a
variabili inesistenti. Quanto segue non verrà compilato:
// ...
Logger.Log(FormatError(ex));
String processo di interpolazione delle String verifica in fase di compilazione , diversamente dalla
stringa di formattazione con string.Format che si verifica in fase di runtime . Le espressioni in una
stringa interpolata devono fare riferimento a nomi nel contesto corrente e devono essere
archiviate in file di risorse. Ciò significa che se vuoi usare la localizzazione devi farlo come:
https://riptutorial.com/it/home 120
// switch to French and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
ShowMyNameLocalized(FirstName);
Se le stringhe di risorse per le lingue utilizzate in precedenza sono archiviate correttamente nei
singoli file di risorse, è necessario ottenere il seguente output:
Nota che ciò implica che il nome segue la stringa localizzata in ogni lingua. In caso contrario, è
necessario aggiungere segnaposti alle stringhe di risorse e modificare la funzione in alto oppure è
necessario interrogare le informazioni sulla cultura nella funzione e fornire un'istruzione switch
case contenente i diversi casi. Per ulteriori dettagli sui file di risorse, vedi Come utilizzare la
localizzazione in C # .
È buona norma utilizzare una lingua di fallback predefinita che la maggior parte delle persone
capirà, nel caso in cui una traduzione non sia disponibile. Suggerisco di usare l'inglese come
lingua di fallback predefinita.
Interpolazione ricorsiva
Sebbene non sia molto utile, è consentito utilizzare una string interpolata ricorsivamente
all'interno delle parentesi graffe di un'altra:
Produzione:
La stringa ha 27 caratteri:
Aspettare e prendere
È possibile utilizzare await espressione Attendi per applicare l'operatore Attendi a Attività o Attività
(di TResult) nel catch e finally blocchi in C # 6.
Non è stato possibile utilizzare l'espressione await nel catch e finally blocchi nelle versioni
https://riptutorial.com/it/home 121
precedenti a causa dei limiti del compilatore. C # 6 rende molto più semplice l'attesa di compiti
asincroni consentendo l'espressione di await .
try
{
//since C#5
await service.InitializeAsync();
}
catch (Exception e)
{
//since C#6
await logger.LogAsync(e);
}
finally
{
//since C#6
await service.CloseAsync();
}
È stato richiesto in C # 5 di usare un bool o dichiarare Exception al di fuori del try catch per
eseguire operazioni asincrone. Questo metodo è mostrato nel seguente esempio:
try
{
// Since C#5
await service.InitializeAsync();
}
catch (Exception e)
{
// Declare bool or place exception inside variable
error = true;
ex = e;
}
Propagazione nulla
Il ?. operatore e operatore ?[...] sono chiamati operatori condizionali nulli . A volte viene anche
indicato con altri nomi come l' operatore di navigazione sicura .
https://riptutorial.com/it/home 122
Questo è utile, perché se il . L'operatore (accessor membro) viene applicato a un'espressione che
restituisce null , il programma genererà NullReferenceException . Se lo sviluppatore utilizza invece
il ?. (null-condizionale), l'espressione valuterà a null invece di generare un'eccezione.
Si noti che se il ?. operatore viene utilizzato e l'espressione non è nullo, ?. e . sono equivalenti.
Nozioni di base
var teacherName = classroom.GetTeacher().Name;
// throws NullReferenceException if GetTeacher() returns null
Visualizza la demo
Se l' classroom non ha un insegnante, GetTeacher() può restituire null . Quando è null e si accede
alla proprietà Name , verrà generata NullReferenceException .
Visualizza la demo
Successivamente, se la classroom potrebbe anche essere null , potremmo scrivere anche questa
affermazione come:
Visualizza la demo
https://riptutorial.com/it/home 123
bool hasCertification = classroom?.GetTeacher()?.HasCertification.GetValueOrDefault();
// must extract value from nullable to assign to a value type variable
Nell'esempio sopra:
https://riptutorial.com/it/home 124
private event EventArgs OnCompleted;
Quando si invoca un evento, tradizionalmente, è consigliabile verificare se l'evento è null nel caso
in cui non siano presenti abbonati:
Poiché è stato introdotto l'operatore null-condizionale, l'invocazione può essere ridotta a una
singola riga:
OnCompleted?.Invoke(EventArgs.Empty);
limitazioni
L'operatore Null-condition produce rvalue, non lvalue, cioè non può essere utilizzato per
l'assegnazione di proprietà, la sottoscrizione di eventi ecc. Ad esempio, il seguente codice non
funzionerà:
gotchas
Nota che:
e quest'ultimo corrisponde a:
https://riptutorial.com/it/home 125
Nonostante l'operatore ternario ?: Qui viene utilizzato per spiegare la differenza tra due casi,
questi operatori non sono equivalenti. Questo può essere facilmente dimostrato con il seguente
esempio:
void Main()
{
var foo = new Foo();
Console.WriteLine("Null propagation");
Console.WriteLine(foo.Bar?.Length);
Console.WriteLine("Ternary");
Console.WriteLine(foo.Bar != null ? foo.Bar.Length : (int?)null);
}
class Foo
{
public string Bar
{
get
{
Console.WriteLine("I was read");
return string.Empty;
}
}
}
Quali uscite:
Propagazione nulla
Sono stato letto
0
Ternario
Sono stato letto
Sono stato letto
0
Visualizza la demo
E questa differenza spiega in qualche modo perché l'operatore di propagazione null non è ancora
supportato negli alberi di espressione.
L' using static [Namespace.Type] direttiva using static [Namespace.Type] consente l'importazione di
membri statici di tipi e valori di enumerazione. I metodi di estensione vengono importati come
metodi di estensione (da un solo tipo), non in ambito di livello superiore.
6.0
https://riptutorial.com/it/home 126
using static System.Console;
using static System.ConsoleColor;
using static System.Math;
class Program
{
static void Main()
{
BackgroundColor = DarkBlue;
WriteLine(Sqrt(2));
}
}
6.0
using System;
class Program
{
static void Main()
{
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.WriteLine(Math.Sqrt(2));
}
}
using System;
public class Program
{
public static void Main()
{
Overloaded(DoSomething);
}
https://riptutorial.com/it/home 127
}
}
risultati:
6.0
Produzione
Visualizza la demo
5.0
Errore
C # 6 può anche gestire bene il seguente caso di corrispondenza esatta per espressioni lambda
che avrebbe comportato un errore in C # 5 .
using System;
class Program
{
static void Foo(Func<Func<long>> func) {}
static void Foo(Func<Func<int>> func) {}
5.0
Console.WriteLine((value: 23));
5.0
https://riptutorial.com/it/home 128
Il compilatore nativo ha permesso questo (anche se ha mostrato un avvertimento), e in
effetti non ha nemmeno controllato la compatibilità del metodo di estensione,
permettendo cose pazzesche come 1.Any is string o IDisposable.Dispose is object .
Nelle versioni precedenti, questo metodo Add doveva essere un metodo di istanza sulla classe da
inizializzare. In C # 6, può anche essere un metodo di estensione.
Questo produrrà:
https://riptutorial.com/it/home 129
Elemento aggiunto con metodo di aggiunta istanza: 2
Elemento aggiunto con metodo di aggiunta istanza: 3
Elemento aggiunto con metodo di aggiunta estensione: 4
Elemento aggiunto con il metodo di aggiunta estensione: 5
Elemento aggiunto con il metodo di aggiunta estensione: 6
In C # 5.0 e precedenti lo sviluppatore poteva solo sopprimere gli avvertimenti per numero. Con
l'introduzione di Roslyn Analyzer, C # ha bisogno di un modo per disabilitare gli avvisi emessi da
librerie specifiche. Con C # 6.0 la direttiva pragma può sopprimere gli avvertimenti per nome.
Prima:
C # 6.0:
https://riptutorial.com/it/home 130
Capitolo 21: C # 7.0 Caratteristiche
introduzione
C # 7.0 è la settima versione di C #. Questa versione contiene alcune nuove funzionalità: supporto
linguistico per Tuple, funzioni locali, dichiarazioni out var , separatori di cifre, valori letterali binari,
corrispondenza di pattern, espressioni di lancio, ref return e ref local list di membri body con
espressioni ref local ed estese.
Examples
out var dichiarazione
Un modello comune in C # sta utilizzando bool TryParse(object input, out object value) per
analizzare in modo sicuro gli oggetti.
La dichiarazione out var è una funzione semplice per migliorare la leggibilità. Permette di
dichiarare una variabile nello stesso momento in cui viene passata come parametro out.
Una variabile dichiarata in questo modo è portata al resto del corpo nel punto in cui è dichiarata.
Esempio
Usando TryParse prima di C # 7.0, devi dichiarare una variabile per ricevere il valore prima di
chiamare la funzione:
7.0
int value;
if (int.TryParse(input, out value))
{
Foo(value); // ok
}
else
{
Foo(value); // value is zero
}
Foo(value); // ok
7.0
https://riptutorial.com/it/home 131
if (int.TryParse(input, out var value))
{
Foo(value); // ok
}
else
{
Foo(value); // value is zero
}
Foo(value); // still ok, the value in scope within the remainder of the body
Se alcuni dei parametri che una funzione ritorna in out non è necessario, è possibile utilizzare
l'operatore di scarto _ .
Una dichiarazione out var può essere utilizzata con qualsiasi funzione esistente che ha già
parametri out . La sintassi della dichiarazione di funzione rimane la stessa e non sono necessari
requisiti aggiuntivi per rendere la funzione compatibile con una dichiarazione out var . Questa
caratteristica è semplicemente zucchero sintattico.
Un'altra caratteristica della dichiarazione out var è che può essere utilizzato con tipi anonimi.
7.0
var a = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var groupedByMod2 = a.Select(x => new
{
Source = x,
Mod2 = x % 2
})
.GroupBy(x => x.Mod2)
.ToDictionary(g => g.Key, g => g.ToArray());
if (groupedByMod2.TryGetValue(1, out var oddElements))
{
Console.WriteLine(oddElements.Length);
}
In questo codice creiamo un Dictionary con chiave int e array di valore di tipo anonimo. Nella
versione precedente di C # era impossibile utilizzare qui il metodo TryGetValue poiché richiedeva di
dichiarare la variabile out (che è di tipo anonimo!). Tuttavia, con out var non è necessario
specificare esplicitamente il tipo di variabile out .
limitazioni
Si noti che le dichiarazioni var out sono di uso limitato nelle query LINQ poiché le espressioni
vengono interpretate come corpi lambda espressione, quindi l'ambito delle variabili introdotte è
limitato a questi lambda. Ad esempio, il seguente codice non funzionerà:
var nums =
from item in seq
https://riptutorial.com/it/home 132
let success = int.TryParse(item, out var tmp)
select success ? tmp : 0; // Error: The name 'tmp' does not exist in the current context
Riferimenti
• Proposta di dichiarazione originale out var su GitHub
Letterali binari
I letterali binari consentono di costruire numeri da zero e uno, il che rende molto più facile vedere
quali bit sono impostati nella rappresentazione binaria di un numero. Questo può essere utile per
lavorare con i flag binari.
I seguenti sono modi equivalenti per specificare un valore int con il valore 34 (= 2 5 + 2 1 ):
// Existing methods:
int a2 = 0x22; // hexadecimal: every digit corresponds to 4 bits
int a3 = 34; // decimal: hard to visualise which bits are set
int a4 = (1 << 5) | (1 << 1); // bitwise arithmetic: combining non-zero bits
Elenchi di bandiere
Prima, specificare i valori dei flag per un enum poteva essere fatto usando uno dei tre metodi in
questo esempio:
[Flags]
public enum DaysOfWeek
{
// Previously available methods:
// decimal hex bit shifting
Monday = 1, // = 0x01 = 1 << 0
Tuesday = 2, // = 0x02 = 1 << 1
Wednesday = 4, // = 0x04 = 1 << 2
Thursday = 8, // = 0x08 = 1 << 3
Friday = 16, // = 0x10 = 1 << 4
Saturday = 32, // = 0x20 = 1 << 5
Sunday = 64, // = 0x40 = 1 << 6
Con i letterali binari è più ovvio quali bit sono impostati e il loro utilizzo non richiede la
comprensione di numeri esadecimali e aritmetica bit a bit:
https://riptutorial.com/it/home 133
[Flags]
public enum DaysOfWeek
{
Monday = 0b00000001,
Tuesday = 0b00000010,
Wednesday = 0b00000100,
Thursday = 0b00001000,
Friday = 0b00010000,
Saturday = 0b00100000,
Sunday = 0b01000000,
Separatori di cifre
Il carattere di sottolineatura _ può essere utilizzato come separatore di cifre. Essere in grado di
raggruppare cifre in grandi valori letterali numerici ha un impatto significativo sulla leggibilità.
Qualsiasi sequenza di cifre può essere separata da uno o più caratteri di sottolineatura. Il _ è
permesso in decimali così come in esponenti. I separatori non hanno alcun impatto semantico:
sono semplicemente ignorati.
Nozioni di base
Una tupla è un elenco di elementi ordinato e finito. Le tuple sono comunemente utilizzate nella
programmazione come mezzo per lavorare collettivamente con una singola entità invece di
https://riptutorial.com/it/home 134
lavorare individualmente con ciascuno degli elementi della tupla e per rappresentare singole righe
(cioè "record") in un database relazionale.
In C # 7.0, i metodi possono avere più valori di ritorno. Dietro le quinte, il compilatore utilizzerà la
nuova struttura ValueTuple .
Nota a margine : per farlo funzionare in Visual Studio 2017, è necessario ottenere il pacchetto
System.ValueTuple .
Se un risultato del metodo tuple-return è assegnato a una singola variabile, è possibile accedere
ai membri con i loro nomi definiti sulla firma del metodo:
int s, c;
(s, c) = GetTallies();
Lo swapping ora è molto più semplice (non è necessaria alcuna variabile temporanea):
https://riptutorial.com/it/home 135
È interessante notare che qualsiasi oggetto può essere decostruito definendo un metodo
Deconstruct nella classe:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
Un approccio alternativo per la classe Person è definire il Name stesso come una Tuple . Considera
quanto segue:
class Person
{
public (string First, string Last) Name { get; }
Quindi puoi istanziare una persona in questo modo (dove possiamo prendere una tupla come
argomento):
https://riptutorial.com/it/home 136
var lastName = person.Name.Last; // "Smith"
Console.WriteLine(name.Item2);
// Outputs Smith
Quando si crea una tupla, è possibile assegnare nomi di elementi ad hoc ai membri della tupla:
Tipo di inferenza
Più tuple definite con la stessa firma (tipi e conteggi corrispondenti) saranno dedotti come tipi
corrispondenti. Per esempio:
statspossono essere restituite poiché la dichiarazione della variabile stats e la firma di ritorno del
metodo sono una corrispondenza.
Mentre la classe ValueTuple stessa non conserva le informazioni per i nomi dei membri, le
informazioni sono disponibili tramite la riflessione in TupleElementNamesAttribute. Questo
attributo non viene applicato alla tupla stessa ma ai parametri del metodo, ai valori restituiti, alle
https://riptutorial.com/it/home 137
proprietà e ai campi. Ciò consente di preservare i nomi delle tuple attraverso gli assembly, ovvero
se un metodo restituisce (nome stringa, conteggio int) il nome e il conteggio dei nomi saranno
disponibili ai chiamanti del metodo in un altro assembly poiché il valore restituito sarà
contrassegnato con TupleElementNameAttribute che contiene i valori "nome" e "conteggio".
Esempio:
if (result == null)
throw new ArgumentException("combo not found");
return result.Item3;
}
https://riptutorial.com/it/home 138
labels = new List<(string firstThingy, string secondThingyLabel, string foundValue)>()
{
("test1", "test2", "Value"),
("test1", "test1", "Value2"),
("test2", "test2", "Value3"),
}
if (result == null)
throw new ArgumentException("combo not found");
return result.foundValue;
}
Sebbene la denominazione sopra la tupla di esempio sopra sia piuttosto generica, l'idea di
etichette pertinenti consente una comprensione più profonda di ciò che viene tentato nel codice
rispetto a "item1", "item2" e "item3".
Riferimenti
• Proposta di caratteristiche linguistiche originali Tuples su GitHub
• Una soluzione VS 15 percorribile per le funzionalità C # 7.0
• NuGet Tuple Package
Funzioni locali
Le funzioni locali sono definite all'interno di un metodo e non sono disponibili al di fuori di esso.
Hanno accesso a tutte le variabili locali e supportano iteratori, async / await e sintassi lambda. In
questo modo, le ripetizioni specifiche di una funzione possono essere funzionalizzate senza
affollare la classe. Come effetto collaterale, questo migliora le prestazioni di suggerimento
intellisense.
https://riptutorial.com/it/home 139
Esempio
double GetCylinderVolume(double radius, double height)
{
return getVolume();
double getVolume()
{
// You can declare inner-local functions in a local function
double GetCircleArea(double r) => Math.PI * r * r;
// ALL parents' variables are accessible even though parent doesn't have any input.
return GetCircleArea(radius) * height;
}
}
Le funzioni locali semplificano considerevolmente il codice per gli operatori LINQ, in cui di solito è
necessario separare i controlli degli argomenti dalla logica effettiva per rendere istantanei gli
assegni degli argomenti, non ritardati fino a dopo l'avvio dell'iterazione.
Esempio
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
return iterator();
IEnumerable<TSource> iterator()
{
foreach (TSource element in source)
if (predicate(element))
yield return element;
}
}
Esempio
async Task WriteEmailsAsync()
{
var emailRegex = new Regex(@"(?i)[a-z0-9_.+-]+@[a-z0-9-]+\.[a-z0-9-.]+");
IEnumerable<string> emails1 = await getEmailsFromFileAsync("input1.txt");
IEnumerable<string> emails2 = await getEmailsFromFileAsync("input2.txt");
await writeLinesToFileAsync(emails1.Concat(emails2), "output.txt");
https://riptutorial.com/it/home 140
{
string text;
Una cosa importante che potresti aver notato è che le funzioni locali possono essere definite sotto
l'istruzione return , non è necessario che siano definite sopra di essa. Inoltre, le funzioni locali in
genere seguono la convenzione di denominazione "lowerCamelCase" per distinguersi più
facilmente dalle funzioni dell'ambito di classe.
Pattern Matching
Le estensioni di pattern matching per C # abilitano molti dei vantaggi dell'abbinamento di pattern
da linguaggi funzionali, ma in un modo che si integra perfettamente con la sensazione del
linguaggio sottostante
switch espressione
Pattern matching estende l' switch dichiarazione per accendere i tipi:
class Geometry {}
https://riptutorial.com/it/home 141
public int Width { get; set; }
}
switch (g)
{
case Triangle t:
Console.WriteLine($"{t.Width} {t.Height} {t.Base}");
break;
case Rectangle sq when sq.Width == sq.Height:
Console.WriteLine($"Square rectangle: {sq.Width} {sq.Height}");
break;
case Rectangle r:
Console.WriteLine($"{r.Width} {r.Height}");
break;
case Square s:
Console.WriteLine($"{s.Width}");
break;
default:
Console.WriteLine("<other>");
break;
}
}
is espressione
La corrispondenza del modello estende l'operatore is per controllare un tipo e dichiarare una
nuova variabile allo stesso tempo.
Esempio
7.0
string s = o as string;
if(s != null)
{
// do something with s
}
7.0
if(o is string s)
{
//Do something with s
};
Si noti inoltre che l'ambito della variabile di pattern s viene esteso al di fuori del blocco if che
raggiunge la fine dell'ambito di inclusione, ad esempio:
https://riptutorial.com/it/home 142
if(someCondition)
{
if(o is string s)
{
//Do something with s
}
else
{
// s is unassigned here, but accessible
}
Ref return e ref locals sono utili per manipolare e restituire riferimenti a blocchi di memoria invece
di copiare memoria senza ricorrere a puntatori non sicuri.
Restituzione
public static ref TValue Choose<TValue>(
Func<bool> condition, ref TValue left, ref TValue right)
{
return condition() ? ref left : ref right;
}
Con questo puoi passare due valori per riferimento con uno di essi restituito in base ad alcune
condizioni:
Ref locale
public static ref int Max(ref int first, ref int second, ref int third)
{
ref int max = first > second ? ref first : ref second;
return max > third ? ref max : ref third;
}
…
int a = 1, b = 2, c = 3;
Max(ref a, ref b, ref c) = 4;
Debug.Assert(a == 1); // true
Debug.Assert(b == 2); // true
Debug.Assert(c == 4); // true
0x0EF00EF0;
Assert.Equal(0xFE, b[0] | b[1] | b[2] | b[3]);
O la Subtract simile:
Inoltre, si può controllare se due ref valori sono uguali stesso indirizzo cioè:
link
Roslyn Github Issue
https://riptutorial.com/it/home 144
System.Runtime.CompilerServices.Unsafe su github
lanciare espressioni
class Person
{
public string Name { get; }
if (spoonsArray == null)
{
throw new Exception("There are no spoons");
}
var spoonsArray = spoons.Length > 0 ? spoons : throw new Exception("There are no spoons");
C # 7.0 aggiunge accessor, costruttori e finalizzatori all'elenco di cose che possono avere corpi di
espressioni:
class Person
https://riptutorial.com/it/home 145
{
private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int,
string>();
ValueTask
è una classe e causa l'inutile sovraccarico della sua allocazione quando il risultato è
Task<T>
immediatamente disponibile.
ValueTask<T> è una struttura ed è stato introdotto per impedire l'allocazione di un oggetto Task nel
caso in cui il risultato dell'operazione asincrona sia già disponibile al momento dell'attesa.
• No allocazione heap se il risultato è noto in modo sincrono (il che non è in questo caso a
causa della Task.Delay , ma spesso è in molti nel mondo reale async / await scenari)
• Prende 65ns con JIT
https://riptutorial.com/it/home 146
}
Ma con ValueTask<T> , le implementazioni sono più libere di scegliere tra l'essere sincrono o
asincrono senza impatto sui chiamanti.
interface IFoo<T>
{
ValueTask<T> BarAsync();
}
Implementazione sincrona:
Implementazione asincrona
https://riptutorial.com/it/home 147
Gli appunti
Sebbene la struttura ValueTask fosse stata pianificata per essere aggiunta a C # 7.0 , per ora è
stata conservata come un'altra libreria. ValueTask <T> Il pacchetto
System.Threading.Tasks.Extensions può essere scaricato dalla Galleria Nuget
https://riptutorial.com/it/home 148
Capitolo 22: C # Script
Examples
Valutazione del codice semplice
https://riptutorial.com/it/home 149
Capitolo 23: caching
Examples
MemoryCache
https://riptutorial.com/it/home 150
Capitolo 24: Classe e metodi parziali
introduzione
Le classi parziali ci forniscono un'opzione per dividere le classi in più parti e in più file sorgente.
Tutte le parti sono combinate in una singola classe durante la compilazione. Tutte le parti
dovrebbero contenere la parola chiave partial , dovrebbero essere della stessa accessibilità.
Tutte le parti devono essere presenti nello stesso assieme per essere incluse durante la
compilazione.
Sintassi
• public partial class MyPartialClass {}
Osservazioni
• Le classi parziali devono essere definite all'interno dello stesso assembly e spazio dei nomi,
come la classe che stanno estendendo.
• Tutte le parti della classe devono avere la stessa accessibilità; public / protected / private
ecc.
• Se una parte utilizza la parola chiave abstract , il tipo combinato viene considerato astratto.
• Se una parte utilizza la parola chiave sealed , il tipo combinato viene considerato sealed.
• Se una parte usa il tipo base, il tipo combinato eredita da quel tipo.
Examples
Lezioni parziali
Le classi parziali forniscono la possibilità di dividere la dichiarazione della classe (di solito in file
separati). Un problema comune che può essere risolto con classi parziali è che consente agli
utenti di modificare il codice generato automaticamente senza temere che le loro modifiche
vengano sovrascritte se il codice viene rigenerato. Inoltre, più sviluppatori possono lavorare sulla
stessa classe o metodi.
using System;
namespace PartialClassAndMethods
{
https://riptutorial.com/it/home 151
public partial class PartialClass
{
public void ExampleMethod() {
Console.WriteLine("Method call from the first declaration.");
}
}
class Program
{
static void Main(string[] args)
{
PartialClass partial = new PartialClass();
partial.ExampleMethod(); // outputs "Method call from the first declaration."
partial.AnotherExampleMethod(); // outputs "Method call from the second
declaration."
}
}
}
Metodi parziali
Il metodo parziale consiste nella definizione in una dichiarazione di classe parziale (come scenario
comune - in quello generato automaticamente) e nell'implementazione in un'altra dichiarazione di
classe parziale.
using System;
namespace PartialClassAndMethods
{
public partial class PartialClass // Auto-generated
{
partial void PartialMethod();
}
class Program
{
static void Main(string[] args)
{
PartialClass partial = new PartialClass();
partial.PartialMethod(); // outputs "Partial method called."
}
}
https://riptutorial.com/it/home 152
}
Quando si eredita da qualsiasi classe base, solo una classe parziale deve avere la classe base
specificata.
// PartialClass1.cs
public partial class PartialClass : BaseClass {}
// PartialClass2.cs
public partial class PartialClass {}
È possibile specificare la stessa classe base in più di una classe parziale. Verrà contrassegnato
come ridondante da alcuni strumenti IDE, ma viene compilato correttamente.
// PartialClass1.cs
public partial class PartialClass : BaseClass {}
// PartialClass2.cs
public partial class PartialClass : BaseClass {} // base class here is redundant
Non è possibile specificare classi di base diverse in più classi parziali, si verificherà un errore del
compilatore.
// PartialClass1.cs
public partial class PartialClass : BaseClass {} // compiler error
// PartialClass2.cs
public partial class PartialClass : OtherBaseClass {} // compiler error
https://riptutorial.com/it/home 153
Capitolo 25: Classi statiche
Examples
Parola chiave statica
1. Questo valore non cambia da oggetto a oggetto, ma piuttosto cambia su una classe nel suo
complesso
2. Le proprietà e i metodi statici non richiedono un'istanza.
//Notice this next call doesn't access the instance but calls by the class name.
Console.WriteLine(Foo.Counter); //this will also print "1"
}
}
Classi statiche
1. Non è possibile creare un'istanza di una classe statica (questo rimuove anche il costruttore
predefinito)
https://riptutorial.com/it/home 154
2. Anche tutte le proprietà e i metodi della classe devono essere statici.
3. Una classe static è una classe sealed , il che significa che non può essere ereditata.
Una classe static è inizializzata pigramente sull'accesso membro e vive per la durata del dominio
dell'applicazione.
void Main()
{
Console.WriteLine("Static classes are lazily initialized");
Console.WriteLine("The static constructor is only invoked when the class is first
accessed");
Foo.SayHi();
https://riptutorial.com/it/home 155
public static class Bar
{
static Bar()
{
Console.WriteLine("static Bar.ctor");
}
}
https://riptutorial.com/it/home 156
Capitolo 26: CLSCompliantAttribute
Sintassi
1. [Assembly: CLSCompliant (true)]
2. [CLSCompliant (true)]
Parametri
Costruttore Parametro
Osservazioni
Common Language Specification (CLS) è un insieme di regole di base a cui deve essere
confermata qualsiasi lingua destinata alla CLI (linguaggio che conferma le specifiche della
Common Language Infrastructure) al fine di interoperare con altri linguaggi conformi a CLS.
Si dovrebbe contrassegnare l'assembly come CLSCompliant nella maggior parte dei casi quando
si distribuiscono le librerie. Questo attributo ti garantirà che il tuo codice sarà utilizzabile da tutte le
lingue compatibili con CLS. Ciò significa che il tuo codice può essere utilizzato da qualsiasi
linguaggio che può essere compilato ed eseguito su CLR ( Common Language Runtime )
Examples
Modificatore di accesso a cui si applicano le regole CLS
using System;
[assembly:CLSCompliant(true)]
namespace CLSDoc
{
https://riptutorial.com/it/home 157
//Warning CS3003 Type of 'Cat.DaysTillVacination' is not CLS-compliant
protected UInt16 DaysTillVacination
{
get { return _daysTillVacination; }
}
return increasedAge;
}
}
}
using System;
[assembly:CLSCompliant(true)]
namespace CLSDoc
{
https://riptutorial.com/it/home 158
return ptr;
}
}
}
using System;
[assembly:CLSCompliant(true)]
namespace CLSDoc
{
}
}
using System;
[assembly:CLSCompliant(true)]
namespace CLSDoc
{
https://riptutorial.com/it/home 159
Violazione della regola CLS: eredita dalla classe non CLSComplaint
using System;
[assembly:CLSCompliant(true)]
namespace CLSDoc
{
[CLSCompliant(false)]
public class Animal
{
public int age = 0;
}
https://riptutorial.com/it/home 160
Capitolo 27: Codice Contratti e asserzioni
Examples
Le asserzioni per verificare la logica dovrebbero sempre essere vere
Le asserzioni vengono utilizzate per non eseguire il test dei parametri di input, ma per verificare
che il flusso del programma sia corretto, ovvero che è possibile formulare determinate ipotesi sul
proprio codice in un determinato momento. In altre parole: un test eseguito con Debug.Assert
presuppone sempre che il valore testato sia true .
Debug.Assert esegue solo in build DEBUG; viene filtrato dalle versioni RELEASE. Deve essere
considerato uno strumento di debug oltre al test delle unità e non come una sostituzione dei
contratti di codice o dei metodi di convalida dell'input.
Qui affermare è una buona scelta perché possiamo presumere che RetrieveSystemConfiguration
() restituirà un valore valido e non restituirà mai null.
Innanzitutto, si può presumere che RetrieveUserData () restituisca un valore valido. Quindi, prima
di utilizzare la proprietà Age, verifichiamo l'ipotesi (che dovrebbe sempre essere vera) che l'età
dell'utente sia strettamente positiva.
Assert non è per la convalida dell'input perché non è corretto presumere che questa asserzione
sarà sempre vera. È necessario utilizzare metodi di convalida dell'input per quello. Nel caso
precedente, dovresti anche verificare che il valore di input sia un numero in primo luogo.
https://riptutorial.com/it/home 161
Capitolo 28: Codice non sicuro in .NET
Osservazioni
• Per poter utilizzare la parola chiave unsafe in un progetto .Net, è necessario selezionare
"Consenti codice non sicuro" in Proprietà progetto => Build
• L'utilizzo di codice non sicuro può migliorare le prestazioni, tuttavia, è a scapito della
sicurezza del codice (quindi il termine unsafe ).
.NET Framework garantisce che non si superi i limiti dell'array, lanciando una
IndexOutOfRangeException se l'indice supera i limiti.
Tuttavia, se si utilizza un codice non sicuro, è possibile superare i limiti dell'array in questo modo:
unsafe
{
fixed (int* ptr = array)
{
for (int i = 0; i <= array.Length; i++)
{
*(ptr+i) = 0;
}
}
}
Examples
Indice di matrice non sicuro
void Main()
{
unsafe
{
int[] a = {1, 2, 3};
fixed(int* b = a)
{
Console.WriteLine(b[4]);
}
}
}
L'esecuzione di questo codice crea una matrice di lunghezza 3, ma poi tenta di ottenere il quinto
elemento (indice 4). Sulla mia macchina, questo stampato 1910457872 , ma il comportamento non è
https://riptutorial.com/it/home 162
definito.
Senza il blocco unsafe , non è possibile utilizzare i puntatori e, pertanto, non è possibile accedere
ai valori oltre la fine di un array senza che venga generata un'eccezione.
Quando si accede agli array con puntatori, non vi è alcun controllo sui limiti e pertanto non verrà
generata IndexOutOfRangeException . Questo rende il codice più veloce.
class Program
{
static void Main(string[] args)
{
unsafe
{
int[] array = new int[1000];
fixed (int* ptr = array)
{
for (int i = 0; i < array.Length; i++)
{
*(ptr+i) = i; //assigning the value with the pointer
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
int[] array = new int[1000];
La parte non sicura sarà generalmente più veloce e la differenza di prestazioni può variare in base
alla complessità degli elementi nell'array e alla logica applicata a ciascuno. Anche se potrebbe
essere più veloce, dovrebbe essere usato con cautela poiché è più difficile da mantenere e più
facile da rompere.
var s = "Hello"; // The string referenced by variable 's' is normally immutable, but
// since it is memory, we could change it if we can access it in an
https://riptutorial.com/it/home 163
// unsafe way.
https://riptutorial.com/it/home 164
Capitolo 29: Come utilizzare C # Structs per
creare un tipo Union (simile a C Unions)
Osservazioni
I tipi dell'Unione sono usati in diverse lingue, in particolare il linguaggio C, per contenere diversi
tipi che possono "sovrapporsi" nello stesso spazio di memoria. In altre parole, potrebbero
contenere diversi campi che iniziano tutti con lo stesso offset di memoria, anche quando
potrebbero avere lunghezze e tipi diversi. Ciò ha il vantaggio sia di risparmiare memoria, sia di
eseguire la conversione automatica.
Si prega di notare i commenti nel costruttore della Struct. L'ordine in cui i campi sono inizializzati è
estremamente importante. Si desidera innanzitutto inizializzare tutti gli altri campi e quindi
impostare il valore che si intende modificare come ultima istruzione. Poiché i campi si
sovrappongono, l'ultima impostazione del valore è quella che conta.
Examples
Unioni stile C in C #
I tipi di unione sono usati in diverse lingue, come il linguaggio C, per contenere diversi tipi che
possono "sovrapporsi". In altre parole, potrebbero contenere diversi campi che iniziano tutti con lo
stesso offset di memoria, anche quando potrebbero avere lunghezze e tipi diversi. Ciò ha il
vantaggio sia di risparmiare memoria, sia di eseguire la conversione automatica. Pensa ad un
indirizzo IP, ad esempio. Internamente, un indirizzo IP viene rappresentato come un numero
intero, ma a volte si desidera accedere al diverso componente Byte, come in
Byte1.Byte2.Byte3.Byte4. Questo funziona per qualsiasi tipo di valore, sia esso primitivo come
Int32 o lungo, o per altre strutture definite dall'utente.
using System;
using System.Runtime.InteropServices;
https://riptutorial.com/it/home 165
{
// When we init the Int, the Bytes will change too.
Address = address;
}
Avendo definito Struct in questo modo, possiamo usarlo come useremmo un'unione in C. Ad
esempio, creiamo un indirizzo IP come numero intero casuale e quindi modifichiamo il primo token
dell'indirizzo su "100", cambiandolo da 'ABCD' a '100.BCD':
Produzione:
75.49.5.32 = 537211211
100.49.5.32 = 537211236
Visualizza la demo
Oltre alle primitive, le strutture di Layout esplicito (Unions) in C #, possono contenere anche altre
strutture. Finché un campo è un tipo di valore e non un riferimento, può essere contenuto in
un'unione:
using System;
using System.Runtime.InteropServices;
// The Service struct will hold the Address, the Port and the Protocol
[StructLayout(LayoutKind.Explicit)]
struct Service
{
[FieldOffset(0)] public IpAddress Address;
[FieldOffset(4)] public ushort Port;
[FieldOffset(6)] public Protocol AppProtocol;
[FieldOffset(0)] public long Payload;
https://riptutorial.com/it/home 166
public Service(IpAddress address, ushort port, Protocol protocol)
{
Payload = 0;
Address = address;
Port = port;
AppProtocol = protocol;
}
Ora possiamo verificare che l'intera Service Union si adatta alle dimensioni di un lungo (8 byte).
Visualizza la demo
Leggi Come utilizzare C # Structs per creare un tipo Union (simile a C Unions) online:
https://riptutorial.com/it/csharp/topic/5626/come-utilizzare-c-sharp-structs-per-creare-un-tipo-
union--simile-a-c-unions-
https://riptutorial.com/it/home 167
Capitolo 30: Commenti e regioni
Examples
Commenti
Usare i commenti nei tuoi progetti è un modo pratico per lasciare delle spiegazioni sulle tue scelte
progettuali e dovrebbe mirare a rendere la tua vita (o di qualcun altro) più semplice quando si
mantiene o si aggiunge al codice.
System.Console.ReadLine();
}
https://riptutorial.com/it/home 168
}
Regioni
Una regione è un blocco di codice comprimibile, che può aiutare con la leggibilità e
l'organizzazione del codice.
NOTA: la regola StyleCop SA1124 DoNotUseRegions scoraggia l'uso delle regioni. Di solito sono
un segno di codice mal organizzato, dato che C # include classi parziali e altre caratteristiche che
rendono le regioni obsolete.
class Program
{
#region Application entry point
static void Main(string[] args)
{
PrintHelloWorld();
System.Console.ReadLine();
}
#endregion
#region My method
private static void PrintHelloWorld()
{
System.Console.WriteLine("Hello, World!");
}
#endregion
}
allargato
https://riptutorial.com/it/home 169
crollato
I commenti della documentazione XML possono essere utilizzati per fornire documentazione API
che può essere facilmente elaborata dagli strumenti:
/// <summary>
/// A helper class for validating method arguments.
/// </summary>
public static class Precondition
{
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> with the parameter
/// name set to <c>paramName</c> if <c>value</c> does not satisfy the
/// <c>predicate</c> specified.
/// </summary>
/// <typeparam name="T">
/// The type of the argument checked
/// </typeparam>
/// <param name="value">
/// The argument to be checked
/// </param>
/// <param name="predicate">
/// The predicate the value is required to satisfy
/// </param>
/// <param name="paramName">
/// The parameter name to be passed to the
/// <see cref="ArgumentOutOfRangeException"/>.
/// </param>
/// <returns>The value specified</returns>
public static T Satisfies<T>(T value, Func<T, bool> predicate, string paramName)
{
if (!predicate(value))
throw new ArgumentOutOfRangeException(paramName);
return value;
}
}
https://riptutorial.com/it/home 170
Leggi Commenti e regioni online: https://riptutorial.com/it/csharp/topic/5346/commenti-e-regioni
https://riptutorial.com/it/home 171
Capitolo 31: Commenti sulla documentazione
XML
Osservazioni
Alcune volte è necessario creare una documentazione di testo estesa dai tuoi commenti xml.
Sfortunatamente non esiste un modo standard per farlo .
Ma ci sono alcuni progetti separati che puoi usare per questo caso:
• Castello di sabbia
• docu
• NDoc
• DocFX
Examples
Annotazione semplice metodo
/// <summary>
/// Bar method description
/// </summary>
public void Bar()
{
Le informazioni all'interno dei tag possono essere utilizzate da Visual Studio e altri strumenti per
fornire servizi come IntelliSense:
https://riptutorial.com/it/home 172
/// <summary>
/// This interface can do Foo
/// </summary>
public interface ICanDoFoo
{
// ...
}
/// <summary>
/// This Bar class implements ICanDoFoo interface
/// </summary>
public class Bar : ICanDoFoo
{
// ...
}
Risultato
Riepilogo dell'interfaccia
/// <summary>
/// Returns the data for the specified ID and timestamp.
/// </summary>
/// <param name="id">The ID for which to get data. </param>
/// <param name="time">The DateTime for which to get data. </param>
/// <returns>A DataClass instance with the result. </returns>
public DataClass GetData(int id, DateTime time)
{
// ...
}
Suggerimento: se Intellisense non viene visualizzato in Visual Studio, eliminare la prima parentesi
o la virgola e quindi digitarlo di nuovo.
https://riptutorial.com/it/home 173
Generazione di XML dai commenti della documentazione
Per generare un file di documentazione XML dai commenti della documentazione nel codice,
utilizzare l'opzione /doc con il compilatore csc.exe C #.
In Visual Studio 2013/2015, In Progetto -> Proprietà -> Crea -> Output , seleziona la casella di
controllo del XML documentation file :
Quando si genera il progetto, il compilatore produrrà un file XML con un nome corrispondente al
nome del progetto (ad es. XMLDocumentation.dll -> XMLDocumentation.xml ).
Quando si utilizza l'assembly in un altro progetto, assicurarsi che il file XML sia nella stessa
directory della DLL a cui si fa il riferimento.
Questo esempio:
/// <summary>
/// Data class description
/// </summary>
public class DataClass
{
/// <summary>
/// Name property description
/// </summary>
public string Name { get; set; }
}
/// <summary>
/// Foo function
/// </summary>
public class Foo
{
/// <summary>
/// This method returning some data
/// </summary>
/// <param name="id">Id parameter</param>
/// <param name="time">Time parameter</param>
/// <returns>Data will be returned</returns>
public DataClass GetData(int id, DateTime time)
{
return new DataClass();
}
}
https://riptutorial.com/it/home 174
Produce questo xml su build:
<?xml version="1.0"?>
<doc>
<assembly>
<name>XMLDocumentation</name>
</assembly>
<members>
<member name="T:XMLDocumentation.DataClass">
<summary>
Data class description
</summary>
</member>
<member name="P:XMLDocumentation.DataClass.Name">
<summary>
Name property description
</summary>
</member>
<member name="T:XMLDocumentation.Foo">
<summary>
Foo function
</summary>
</member>
<member name="M:XMLDocumentation.Foo.GetData(System.Int32,System.DateTime)">
<summary>
This method returning some data
</summary>
<param name="id">Id parameter</param>
<param name="time">Time parameter</param>
<returns>Data will be returned</returns>
</member>
</members>
</doc>
Il tag <see> può essere utilizzato per collegarsi a un'altra classe. Contiene il membro cref che
dovrebbe contenere il nome della classe a cui fare riferimento. Visual Studio fornirà Intellsense
durante la scrittura di questo tag e tali riferimenti verranno elaborati anche in caso di
ridenominazione della classe di riferimento.
/// <summary>
/// You might also want to check out <see cref="SomeOtherClass"/>.
/// </summary>
public class SomeClass
{
}
Nei popup di Visual Studio Intellisense tali riferimenti verranno visualizzati anche colorati nel testo.
Per fare riferimento a una classe generica, utilizzare qualcosa di simile al seguente:
/// <summary>
/// An enhanced version of <see cref="List{T}"/>.
/// </summary>
public class SomeGenericClass<T>
https://riptutorial.com/it/home 175
{
}
https://riptutorial.com/it/home 176
Capitolo 32: Comprese le risorse di carattere
Parametri
Parametro Dettagli
Examples
Istanziare 'Fontfamily' da Risorse
Metodo di integrazione
https://riptutorial.com/it/home 177
return pfc.Families[0];
}
https://riptutorial.com/it/home 178
Capitolo 33: Contesto di sincronizzazione in
attesa asincrona
Examples
Pseudocodice per parole chiave asincrone / attese
Semplificando, possiamo dire che questo codice in realtà significa quanto segue:
Task Foo()
{
Bar();
Task t = Baz();
var context = SynchronizationContext.Current;
t.ContinueWith(task) =>
{
if (context == null)
Qux();
else
context.Post((obj) => Qux(), null);
}, TaskScheduler.Current);
return t;
}
Significa che le parole chiave async / await il contesto di sincronizzazione corrente se esiste. Ad
esempio, è possibile scrivere codice di libreria che funzioni correttamente in applicazioni UI, Web
e Console.
Articolo di origine
. . .
https://riptutorial.com/it/home 179
Foo().ConfigureAwait(false);
Ma questo codice non verrà eseguito perché il corpo interno può essere eseguito su thread non UI
e non dovrebbe modificare direttamente le proprietà dell'interfaccia utente :
if (label1.InvokeRequired)
lable1.BeginInvoke((Action) delegate() { label1.Text = label1Text; });
else
label1.Text = label1Text;
});
}
Ora non dimenticare di usare sempre questo modello. Oppure prova SynchronizationContext.Post
che lo farà per te:
https://riptutorial.com/it/home 180
SynchronizationContext.Current.Post((obj) =>
{
label1.Text = label1 Text);
}, null);
});
}
https://riptutorial.com/it/home 181
Capitolo 34: Contratti di codice
Sintassi
1. Contract.Requires (Condizione, UserMessage)
Contract.Result <T>
Contract.Ensures ()
Contract.Invariants ()
Osservazioni
.NET supporta l'idea Design by Contract tramite la classe Contracts presente nello spazio dei
nomi System.Diagnostics e introdotta in .NET 4.0. Code Contracts API include classi per il
controllo statico e di runtime del codice e consente di definire precondizioni, postcondizioni e
invarianti all'interno di un metodo. Le condizioni preliminari specificano le condizioni che i
parametri devono soddisfare prima che un metodo possa essere eseguito, le postcondizioni
verificate al completamento di un metodo e le invarianti definiscono le condizioni che non
cambiano durante l'esecuzione di un metodo.
Tenere traccia dei problemi di un'applicazione quando la tua applicazione è in esecuzione, è una
delle preoccupazioni principali di tutti gli sviluppatori e amministratori. Il monitoraggio può essere
eseguito in molti modi. Per esempio -
I Contratti di codice utilizzano un approccio diverso per il rilevamento e la gestione dei problemi
all'interno di un'applicazione. Invece di convalidare tutto ciò che viene restituito da una chiamata di
metodo, Contratti di codice con l'aiuto di precondizioni, postcondizioni e invarianti sui metodi,
assicurarsi che tutto ciò che entra e che lasci i metodi sia corretto.
Examples
https://riptutorial.com/it/home 182
presupposti
namespace CodeContractsDemo
{
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
this._payments.Add(payment);
}
}
}
postconditions
return total;
}
invarianti
namespace CodeContractsDemo
{
using System;
using System.Diagnostics.Contracts;
public Point()
{
}
https://riptutorial.com/it/home 183
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
[ContractInvariantMethod]
private void ValidateCoordinates()
{
Contract.Invariant(this.X >= 0);
Contract.Invariant(this.Y >= 0);
}
}
}
[ContractClass(typeof(ValidationContract))]
interface IValidation
{
string CustomerID{get;set;}
string Password{get;set;}
}
[ContractClassFor(typeof(IValidation))]
sealed class ValidationContract:IValidation
{
string IValidation.CustomerID
{
[Pure]
get
{
return Contract.Result<string>();
}
set
{
https://riptutorial.com/it/home 184
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(value), "Customer
ID cannot be null!!");
}
}
string IValidation.Password
{
[Pure]
get
{
return Contract.Result<string>();
}
set
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(value), "Password
cannot be null!!");
}
}
}
class Validation:IValidation
{
public string GetCustomerPassword(string customerID)
{
Contract.Requires(!string.IsNullOrEmpty(customerID),"Customer ID cannot be Null");
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(customerID),
"Exception!!");
Contract.Ensures(Contract.Result<string>() != null);
string password="AAA@1234";
if (customerID!=null)
{
return password;
}
else
{
return null;
}
https://riptutorial.com/it/home 185
{
m_PWD = value;
}
}
}
Nel codice precedente, abbiamo definito un'interfaccia chiamata IValidation con un attributo
[ContractClass] . Questo attributo prende un indirizzo di una classe in cui abbiamo implementato
un contratto per un'interfaccia. La classe ValidationContract utilizza le proprietà definite
nell'interfaccia e verifica i valori null utilizzando Contract.Requires<T> . T è una classe di eccezione.
Abbiamo anche contrassegnato l'accesso get con un attributo [Pure] . L'attributo puro garantisce
che il metodo o una proprietà non modifichi lo stato dell'istanza di una classe in cui è
implementata l'interfaccia di IValidation .
https://riptutorial.com/it/home 186
Capitolo 35: Convenzioni di denominazione
introduzione
Questo argomento delinea alcune convenzioni di denominazione di base utilizzate durante la
scrittura nel linguaggio C #. Come tutte le convenzioni, non sono applicate dal compilatore, ma
assicurano la leggibilità tra gli sviluppatori.
Osservazioni
Inoltre, evita l'uso di identificatori in conflitto con le parole chiave già utilizzate in C #.
Abbreviazioni e Acronimi
In generale, non si dovrebbero usare abbreviazioni o acronimi; questi rendono i tuoi nomi meno
leggibili. Allo stesso modo, è difficile sapere quando è sicuro assumere che un acronimo è
ampiamente riconosciuto.
Examples
Convenzioni sulla capitalizzazione
https://riptutorial.com/it/home 187
I seguenti termini descrivono diversi modi per identificare i casi.
Involucro Pascal
La prima lettera nell'identificatore e la prima lettera di ogni parola concatenata successiva sono in
maiuscolo. È possibile utilizzare il caso Pascal per identificatori di tre o più caratteri. Ad esempio:
BackColor
Camel Casing
La prima lettera di un identificatore è in minuscolo e la prima lettera di ogni parola concatenata
successiva è in maiuscolo. Ad esempio: backColor
Lettere maiuscole
Tutte le lettere nell'identificatore sono in maiuscolo. Ad esempio: IO
Regole
Quando un identificatore è costituito da più parole, non utilizzare separatori, come caratteri di
sottolineatura ("_") o trattini ("-"), tra le parole. Invece, usa l'involucro per indicare l'inizio di ogni
parola.
La tabella seguente riepiloga le regole di maiuscole per gli identificatori e fornisce esempi per i
diversi tipi di identificatori:
https://riptutorial.com/it/home 188
Identifier Astuccio Esempio
interfacce
Le interfacce devono essere denominate con nomi o frasi di nomi o aggettivi che descrivono il
comportamento. Per esempio IComponent usa un nome descrittivo, ICustomAttributeProvider usa
una frase nominale e IPersistable usa un aggettivo.
I nomi dell'interfaccia devono essere preceduti dalla lettera I , per indicare che il tipo è
un'interfaccia e deve essere utilizzato il caso Pascal.
Campi privati
https://riptutorial.com/it/home 189
// Names are unique, so "this" keyword is not required
_numerator = numerator;
_denominator = denominator;
}
}
Namespace
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>].
Esempi inclusi:
Fabrikam.Math
Litware.Security
Il prefisso dei nomi di spazi dei nomi con il nome di una società impedisce agli spazi dei nomi di
società diverse di avere lo stesso nome.
Enums
Utilizzare un nome plurale per i tipi Enum che sono campi bit
[Flags]
public enum MyColors
{
Yellow = 1,
Green = 2,
Red = 4,
Blue = 8
}
https://riptutorial.com/it/home 190
Non usare il nome enum in ciascuna voce
eccezioni
https://riptutorial.com/it/home 191
Capitolo 36: Costrutti di flusso di dati di Task
Parallel Library (TPL)
Examples
JoinBlock
Come BatchBlock, JoinBlock <T1, T2, ...> è in grado di raggruppare i dati da più origini dati. In
effetti, questo è lo scopo principale di JoinBlock <T1, T2, ...>.
Ad esempio, un JoinBlock <string, double, int> è un ISourceBlock <Tuple <string, double, int >>.
Come con BatchBlock, JoinBlock <T1, T2, ...> è in grado di funzionare sia in modalità avida che
non avida.
• Nella modalità greedy di default, tutti i dati offerti ai target sono accettati, anche se l'altro
target non ha i dati necessari con cui formare una tupla.
• In modalità non greedy, i target del blocco posticiperanno i dati fino a quando a tutti i target
non saranno stati offerti i dati necessari per creare una tupla, a quel punto il blocco si
impegnerà in un protocollo di commit a due fasi per recuperare atomicamente tutti gli
elementi necessari dalle fonti. Questo rinvio consente a un'altra entità di consumare i dati nel
frattempo in modo da consentire al sistema complessivo di avanzare.
request.ProcessWith(resource);
return resource;
});
https://riptutorial.com/it/home 192
throttle.LinkTo(processor);
processor.LinkTo(throttle.Target1);
BroadcastBlock
Inoltre, a differenza di BufferBlock, BroadcastBlock non mantiene i dati inutilmente. Dopo che un
particolare dato è stato offerto a tutti i bersagli, quell'elemento sarà sovrascritto da qualunque
pezzo di dati è in linea (come con tutti i blocchi di flusso di dati, i messaggi sono gestiti in ordine
FIFO). Questo elemento sarà offerto a tutti gli obiettivi, e così via.
var ui = TaskScheduler.FromCurrentSynchronizationContext();
var bb = new BroadcastBlock<ImageData>(i => i);
bb.LinkTo(saveToDiskBlock);
bb.LinkTo(showInUiBlock);
public MyAgent()
{
https://riptutorial.com/it/home 193
Status = new BroadcastBlock<string>();
Run();
}
WriteOnceBlock
(Variabile di sola lettura: memorizza il suo primo elemento di dati e ne distribuisce copie come
output. Ignora tutti gli altri elementi di dati)
Puoi pensare a WriteOnceBlock come simile a una variabile membro readonly in C #, ma invece
di essere solo impostabile in un costruttore e quindi immutabile, è impostabile solo una volta ed è
quindi immutabile.
try
{
result.Post(await task);
}
catch(Exception ex)
{
exception.Post(ex);
}
}
https://riptutorial.com/it/home 194
Introduzione a TPL Dataflow di Stephen Toub
BatchedJoinBlock
(Raccoglie un certo numero di elementi totali da 2-3 input e li raggruppa in una tupla di raccolte di
elementi di dati)
BatchedJoinBlock <T1, T2, ...> è in un certo senso una combinazione di BatchBlock e JoinBlock
<T1, T2, ...>.
Mentre JoinBlock <T1, T2, ...> viene utilizzato per aggregare un input da ciascun target in una
tupla e BatchBlock viene utilizzato per aggregare N input in una raccolta, BatchJoinBlock <T1, T2,
...> viene utilizzato per raccogliere N input da across tutti gli obiettivi in tuple di raccolte.
Scatter / gather
foreach(string s in results.Item1)
{
Console.WriteLine(s);
}
foreach(Exception e in results.Item2)
{
Console.WriteLine(e);
}
TransformBlock
https://riptutorial.com/it/home 195
Come con ActionBlock, TransformBlock <TInput, TOutput> consente l'esecuzione di un delegato
per eseguire alcune azioni per ogni dato di input; a differenza di ActionBlock, questa
elaborazione ha un output. Questo delegato può essere un Func <TInput, TOutput>, nel qual
caso l'elaborazione di quell'elemento viene considerata completata al ritorno del delegato oppure
può essere Func <TInput, Task>, nel qual caso l'elaborazione di quell'elemento viene considerata
completata quando il delegato ritorna ma quando l'attività restituita è completa. Per chi ha
familiarità con LINQ, è in qualche modo simile a Select () in quanto richiede un input, trasforma
quell'input in qualche modo e quindi produce un output.
Per impostazione predefinita, TransformBlock <TInput, TOutput> elabora i suoi dati in modo
sequenziale con un MaxDegreeOfParallelism uguale a 1. Oltre a ricevere l'input bufferizzato ed
elaborarlo, questo blocco prenderà tutti i suoi output elaborati e anche il buffer (dati che non sono
stati elaborati e dati che sono stati elaborati).
Ha 2 compiti: uno per elaborare i dati e uno per spingere i dati al blocco successivo.
compressor.LinkTo(Encryptor);
ActionBlock
(per ciascuno)
Questa classe può essere considerata logicamente come un buffer per i dati da elaborare in
combinazione con le attività per l'elaborazione di tali dati, con il "blocco del flusso di dati" che
gestisce entrambi. Nel suo uso più basilare, possiamo istanziare un oggetto ActionBlock e
"postare" i dati su di esso; il delegato fornito alla costruzione di ActionBlock verrà eseguito in
modo asincrono per ogni dato inviato.
https://riptutorial.com/it/home 196
Calcolo sincrono
downloader.Post("http://website.com/path/to/images");
downloader.Post("http://another-website.com/path/to/images");
TransformManyBlock
(SelectMany, 1-m: i risultati di questa mappatura sono "appiattiti", proprio come SelectMany di
LINQ)
Un Func <TInput, IEnumerable> viene utilizzato per synchronous e un Func <TInput, Task
<IEnumerable >> viene utilizzato per asincrono. Come con ActionBlock e TransformBlock <TInput,
TOutput>, TransformManyBlock <TInput, TOutput> passa automaticamente all'elaborazione
sequenziale, ma può essere configurato diversamente.
Il delegato di mappatura retunisce una raccolta di elementi, che vengono inseriti singolarmente nel
buffer di output.
https://riptutorial.com/it/home 197
Web crawler asincrono
return Enumerable.Empty<string>();
});
downloader.LinkTo(downloader);
BatchBlock
BatchBlock combina N singoli elementi in un unico articolo, rappresentato come una matrice di
elementi. Un'istanza viene creata con una specifica dimensione di batch e il blocco crea quindi un
batch non appena viene ricevuto quel numero di elementi, in modo asincrono che invia il batch al
buffer di output.
• Nella modalità greedy di default, tutti i messaggi offerti al blocco da qualsiasi numero di fonti
sono accettati e memorizzati nel buffer per essere convertiti in batch.
• ○ In modalità non avida, tutti i messaggi vengono posticipati dalle fonti finché un numero
sufficiente di fonti non ha offerto messaggi al blocco per creare un batch. Quindi, un
BatchBlock può essere usato per ricevere 1 elemento da ciascuna delle fonti N, da N
elementi da 1 fonte e da una miriade di opzioni intermedie.
https://riptutorial.com/it/home 198
Richieste di raggruppamento in gruppi di 100 da inviare a un database
batchRequests.LinkTo(sendToDb);
BufferBlock
// Producer
private static async void Producer()
{
while(true)
{
await _Buffer.SendAsync(Produce());
https://riptutorial.com/it/home 199
}
}
// Consumer
private static async Task Consumer()
{
while(true)
{
Process(await _Buffer.ReceiveAsync());
}
}
https://riptutorial.com/it/home 200
Capitolo 37: Costruttori e Finalizzatori
introduzione
I costruttori sono metodi in una classe che vengono invocati quando viene creata un'istanza di
quella classe. La loro principale responsabilità è quella di lasciare il nuovo oggetto in uno stato
utile e coerente.
I distruttori / finalizzatori sono metodi di una classe invocati quando un'istanza viene distrutta. In C
# raramente vengono scritti / utilizzati esplicitamente.
Osservazioni
C # non ha effettivamente distruttori, ma piuttosto Finalizzatori che usano la sintassi del distruttore
di stile C ++. La specifica di un distruttore sovrascrive il metodo Object.Finalize() che non può
essere chiamato direttamente.
A differenza di altri linguaggi con sintassi simile, questi metodi non vengono chiamati quando gli
oggetti escono dall'ambito, ma vengono chiamati quando viene eseguito il Garbage Collector, che
si verifica in determinate condizioni . Come tali, essi non sono garantiti per l'esecuzione in un
ordine particolare.
I finalizzatori dovrebbero essere responsabili della pulizia solo delle risorse non gestite (puntatori
acquisiti tramite la classe Marshal, ricevuti tramite p / Invoke (chiamate di sistema) o puntatori
grezzi utilizzati all'interno di blocchi non sicuri). Per ripulire le risorse gestite, rivedere IDisposable,
il pattern Dispose e l'istruzione using .
Examples
Costruttore predefinito
https://riptutorial.com/it/home 201
La definizione di qualsiasi costruttore per il tipo sopprimerà la generazione predefinita del
costruttore. Se il tipo è stato definito come segue:
// This is valid
var myAnimal = new Animal("Fluffy");
// This fails to compile
var unnamedAnimal = new Animal();
Se si desidera che una classe abbia sia un costruttore senza parametri sia un costruttore che
accetta un parametro, è possibile farlo implementando esplicitamente entrambi i costruttori.
Il compilatore non sarà in grado di generare un costruttore predefinito se la classe estende un'altra
classe che non ha un costruttore senza parametri. Ad esempio, se avessimo una Creature classe:
quindi Animal definito come class Animal : Creature {} non verrebbe compilato.
https://riptutorial.com/it/home 202
}
Costruttore statico
Un costruttore statico viene chiamato la prima volta che viene inizializzato un membro di un tipo,
viene chiamato un membro di classe statico o un metodo statico. Il costruttore statico è thread-
safe. Un costruttore statico è comunemente usato per:
• Inizializza lo stato statico, ovvero lo stato che è condiviso tra diverse istanze della stessa
classe.
• Crea un singleton
Esempio:
class Animal
{
// * A static constructor is executed only once,
// when a class is first accessed.
// * A static constructor cannot have any access modifiers
// * A static constructor cannot have any parameters
static Animal()
{
Console.WriteLine("Animal initialized");
}
Produzione:
Animale inizializzato
Animale creato
Animale creato
Visualizza la demo
Se la prima chiamata riguarda un metodo statico, il costruttore statico viene richiamato senza il
costruttore dell'istanza. Questo è OK, perché il metodo statico non può accedere allo stato di
istanza in ogni caso.
https://riptutorial.com/it/home 203
Animal.Yawn();
Questo produrrà:
Animale inizializzato
Sbadiglio!
Esempio Singleton:
static SessionManager()
{
Instance = new SessionManager();
}
}
Un costruttore di una classe base viene chiamato prima che venga eseguito un costruttore di una
classe derivata. Ad esempio, se Mammal estende Animal , il codice contenuto nel costruttore di
Animal viene chiamato prima quando si crea un'istanza di un Mammal .
Se una classe derivata non specifica esplicitamente quale costruttore della classe base deve
essere chiamato, il compilatore assume il costruttore senza parametri.
In questo caso, l'istanzializzazione di un Mammal chiamando il new Mammal("George the Cat") verrà
stampata
Visualizza la demo
La chiamata a un diverso costruttore della classe base viene effettuata posizionando : base(args)
https://riptutorial.com/it/home 204
tra la firma del costruttore e il suo corpo:
Visualizza la demo
class TheBaseClass
{
~TheBaseClass()
{
Console.WriteLine("Base class finalized!");
}
}
https://riptutorial.com/it/home 205
private SingletonClass()
{
// Put custom constructor code here
}
}
Poiché il costruttore è privato, non è possibile creare nuove istanze di SingletonClass mediante il
consumo di codice. L'unico modo per accedere alla singola istanza di SingletonClass consiste
nell'utilizzare la proprietà statica SingletonClass.Instance .
Nota che se il costruttore statico fallisce, la classe Singleton diventa definitivamente inutilizzabile
per la vita di AppDomain.
Inoltre, non è garantito il funzionamento del costruttore statico al momento del primo accesso di
Instance . Piuttosto, funzionerà prima o poi . Questo rende il momento in cui l'inizializzazione
avviene non deterministica. Nei casi pratici, il JIT chiama spesso il costruttore statico durante la
compilazione (non l'esecuzione) di un metodo che fa riferimento Instance . Questa è
un'ottimizzazione delle prestazioni.
Vedere la pagina Implementazioni Singleton per altri modi per implementare il modello singleton.
Sebbene i costruttori statici vengano sempre chiamati prima del primo utilizzo di un tipo, talvolta è
utile poterli forzare a chiamare e la classe RuntimeHelpers fornisce un helper per questo:
using System.Runtime.CompilerServices;
// ...
RuntimeHelpers.RunClassConstructor(typeof(Foo).TypeHandle);
Osservazione : verrà eseguita tutta l'inizializzazione statica (ad esempio gli inizializzatori dei
campi), non solo il costruttore stesso.
https://riptutorial.com/it/home 206
_obj = CreateAnother();
}
Se provieni da uno sfondo C ++ questo è sorprendente, il costruttore della classe base vede già la
tabella del metodo virtuale della classe derivata!
Attenzione : la classe derivata potrebbe non essere stata ancora completamente inizializzata (il
suo costruttore verrà eseguito dopo il costruttore della classe base) e questa tecnica è pericolosa
(c'è anche un avvertimento StyleCop per questo). Di solito questo è considerato una cattiva
pratica.
Se il tipo su cui è dichiarato il costruttore statico è generico, il costruttore statico verrà chiamato
una volta per ogni combinazione univoca di argomenti generici.
class Animal<T>
{
static Animal()
{
Console.WriteLine(typeof(T).FullName);
}
Animal<Object>.Yawn();
Animal<String>.Yawn();
Questo produrrà:
System.Object
System.String
https://riptutorial.com/it/home 207
Vedi anche Come funzionano i costruttori statici per tipi generici?
Se un costruttore statico genera un'eccezione, non viene mai ripetuto. Il tipo è inutilizzabile per la
durata di AppDomain. Qualsiasi ulteriore utilizzo del tipo genererà una TypeInitializationException
racchiusa TypeInitializationException originale.
try
{
Animal.Yawn();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
try
{
Animal.Yawn();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Questo produrrà:
Agente statico
[...]
dove puoi vedere che il costruttore vero e proprio viene eseguito una sola volta e l'eccezione
viene riutilizzata.
https://riptutorial.com/it/home 208
Inizializzazione costruttore e proprietà
Il compito del valore della proprietà deve essere eseguito prima o dopo il costruttore della classe?
public TestClass()
{
if (TestProperty == 1)
{
Console.WriteLine("Shall this be executed?");
}
if (TestProperty == 2)
{
Console.WriteLine("Or shall this be executed");
}
}
}
Nell'esempio sopra, il valore TestProperty deve essere 1 nel costruttore della classe o dopo il
costruttore della classe?
Assegnazione dei valori delle proprietà nella creazione dell'istanza in questo modo:
Verrà eseguito dopo l'esecuzione del costruttore. Tuttavia, inizializzando il valore della proprietà
nella proprietà della classe in C # 6.0 in questo modo:
public TestClass()
{
}
}
public TestClass()
https://riptutorial.com/it/home 209
{
if (TestProperty == 1)
{
Console.WriteLine("Shall this be executed?");
}
if (TestProperty == 2)
{
Console.WriteLine("Or shall this be executed");
}
}
}
Risultato finale:
Spiegazione:
Il valore TestProperty verrà prima assegnato come 2 , quindi verrà eseguito il costruttore TestClass ,
con conseguente stampa di
E quindi TestProperty verrà assegnato come 1 causa del new TestClass() { TestProperty = 1 } ,
rendendo il valore finale per TestProperty stampato da
Console.WriteLine(testInstance.TestProperty) da
"1"
https://riptutorial.com/it/home 210
Capitolo 38: Creazione del proprio
MessageBox nell'applicazione Windows
Form
introduzione
Per prima cosa dobbiamo sapere cos'è un MessageBox ...
Sintassi
• 'static DialogResult result = DialogResult.No; // DialogResult viene restituito dalle finestre di
dialogo dopo il licenziamento. '
Examples
Creazione del proprio controllo MessageBox.
Per creare il nostro controllo MessageBox basta seguire la guida qui sotto ...
2. Vai alla barra degli strumenti in alto e fai clic su File -> Nuovo progetto -> Applicazione
Windows Form -> Assegna un nome al progetto, quindi fai clic su OK.
3. Una volta caricato, trascinare e rilasciare un pulsante di controllo dalla casella degli
strumenti (che si trova a sinistra) sul modulo (come mostrato di seguito).
https://riptutorial.com/it/home 211
4. Fare doppio clic sul pulsante e l'Integrated Development Environment genererà
automaticamente il gestore di eventi click per te.
5. Modificare il codice per il modulo in modo che assomigli al seguente (è possibile fare clic con
il pulsante destro del mouse sul modulo e fare clic su Modifica codice):
namespace MsgBoxExample {
public partial class MsgBoxExampleForm : Form {
//Constructor, called when the class is initialised.
public MsgBoxExampleForm() {
InitializeComponent();
}
6. Solution Explorer -> Fare clic con il tasto destro sul progetto -> Aggiungi -> Windows Form e
impostare il nome come "CustomMsgBox.cs"
7. Trascina un pulsante e un controllo etichetta dalla casella degli strumenti al modulo (dopo
averlo visualizzato sarà simile al modulo seguente:
https://riptutorial.com/it/home 212
8. Ora scrivi il codice qui sotto nel modulo appena creato:
9. Ora esegui il programma premendo il tasto F5. Congratulazioni, hai fatto un controllo
riutilizzabile.
Per trovare i file .cs esistenti, fare clic con il tasto destro del mouse sul progetto nell'istanza di
Visual Studio e fare clic su Apri cartella in Esplora file.
1. Visual Studio -> Il tuo progetto corrente (Windows Form) -> Esplora soluzioni -> Nome
progetto -> Clic destro -> Aggiungi -> Oggetto esistente -> Quindi individua il tuo file .cs
esistente.
2. Ora c'è un'ultima cosa da fare per usare il controllo. Aggiungi un'istruzione using al tuo
codice, in modo che l'assembly possa conoscere le sue dipendenze.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
.
.
https://riptutorial.com/it/home 213
.
using CustomMsgBox; //Here's the using statement for our dependency.
CustomMsgBox.Show ("Il tuo messaggio per Message Box ...", "MSG", "OK");
https://riptutorial.com/it/home 214
Capitolo 39: Creazione di un'applicazione
console utilizzando un Editor di testo
semplice e il compilatore C # (csc.exe)
Examples
Creazione di un'applicazione console utilizzando un Editor di testo semplice e
il compilatore C #
Per utilizzare un editor di testo semplice per creare un'applicazione console scritta in C #, è
necessario il compilatore C #. Il compilatore C # (csc.exe) può essere trovato nel seguente
percorso: %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe
NB In base alla versione di .NET Framework installata nel sistema, potrebbe essere necessario
modificare di conseguenza il percorso sopra riportato.
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe
/out:"C:\Users\yourUserName\Documents\ConsoleApp.exe"
"C:\Users\yourUserName\Documents\ConsoleApp.cs"
Ora, torna al punto in cui hai salvato in origine il tuo file ConsoleApp.cs . Ora dovresti vedere un file
https://riptutorial.com/it/home 215
eseguibile ( ConsoleApp.exe ). Fare doppio clic su ConsoleApp.exe per aprirlo.
Questo è tutto! La tua applicazione per la console è stata compilata. È stato creato un file
eseguibile e ora hai un'app Console funzionante.
using System;
namespace ConsoleApp
{
class Program
{
private static string input = String.Empty;
DisplayGreeting:
{
Console.WriteLine("Hello! What is your name?");
input = Console.ReadLine();
if (input.Length >= 1)
{
Console.WriteLine(
"Hello, " +
input +
", enter 'Exit' at any time to exit this app.");
goto AwaitFurtherInstruction;
}
else
{
goto DisplayGreeting;
}
}
AwaitFurtherInstruction:
{
input = Console.ReadLine();
if(input.ToLower() == "exit")
{
input = String.Empty;
Environment.Exit(0);
}
else
{
goto AwaitFurtherInstruction;
}
}
}
}
}
https://riptutorial.com/it/home 216
console-utilizzando-un-editor-di-testo-semplice-e-il-compilatore-c-sharp--csc-exe-
https://riptutorial.com/it/home 217
Capitolo 40: Crittografia
(System.Security.Cryptography)
Examples
Esempi moderni di crittografia autenticata simmetrica di una stringa
La crittografia è qualcosa di molto difficile e dopo aver passato molto tempo a leggere diversi
esempi e vedere quanto sia facile introdurre una qualche forma di vulnerabilità ho trovato una
risposta originariamente scritta da @jbtule che ritengo sia molto buona. Buona lettura:
"La migliore medicina generale per la crittografia simmetrica è quello di utilizzare la crittografia
autenticato con Associated Data (AEAD), tuttavia questo non è una parte delle librerie
crittografiche .net standard. Quindi il primo esempio utilizza AES256 e poi HMAC256 , a due step
Encrypt poi MAC , che richiede più overhead e più chiavi.
Il secondo esempio utilizza la pratica più semplice di AES256- GCM utilizzando il castello di
Bouncy open source (via nuget).
Entrambi gli esempi hanno una funzione principale che accetta una stringa di messaggio segreta,
una o più chiavi e un payload e una stringa crittografati facoltativi e non crittografati
facoltativamente preceduti dai dati non segreti. Idealmente NewKey() questi con chiavi a 256 bit
generate casualmente, vedi NewKey() .
Entrambi gli esempi hanno anche metodi di supporto che utilizzano una password di stringa per
generare le chiavi. Questi metodi di supporto sono forniti per comodità con altri esempi, tuttavia
sono molto meno sicuri perché la forza della password sarà molto più debole di una chiave a 256
bit .
/*
* This work (Modern Encryption of a String C#, by James Tuley),
* identified by James Tuley, is free of known copyright restrictions.
* https://gist.github.com/4336842
* http://creativecommons.org/publicdomain/mark/1.0/
*/
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Encryption
https://riptutorial.com/it/home 218
{
public static class AESThenHMAC
{
private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();
/// <summary>
/// Helper that generates a random key on each call.
/// </summary>
/// <returns></returns>
public static byte[] NewKey()
{
var key = new byte[KeyBitSize / 8];
Random.GetBytes(key);
return key;
}
/// <summary>
/// Simple Encryption (AES) then Authentication (HMAC) for a UTF8 Message.
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="cryptKey">The crypt key.</param>
/// <param name="authKey">The auth key.</param>
/// <param name="nonSecretPayload">(Optional) Non-Secret Payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Secret Message
Required!;secretMessage</exception>
/// <remarks>
/// Adds overhead of (Optional-Payload + BlockSize(16) + Message-Padded-To-Blocksize +
HMac-Tag(32)) * 1.33 Base64
/// </remarks>
public static string SimpleEncrypt(string secretMessage, byte[] cryptKey, byte[] authKey,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
/// <summary>
/// Simple Authentication (HMAC) then Decryption (AES) for a secrets UTF8 Message.
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="cryptKey">The crypt key.</param>
/// <param name="authKey">The auth key.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
https://riptutorial.com/it/home 219
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message
Required!;encryptedMessage</exception>
public static string SimpleDecrypt(string encryptedMessage, byte[] cryptKey, byte[]
authKey,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");
/// <summary>
/// Simple Encryption (AES) then Authentication (HMAC) of a UTF8 message
/// using Keys derived from a Password (PBKDF2).
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayload">The non secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">password</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// Adds additional non secret payload for key generation parameters.
/// </remarks>
public static string SimpleEncryptWithPassword(string secretMessage, string password,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
/// <summary>
/// Simple Authentication (HMAC) and then Descryption (AES) of a UTF8 Message
/// using keys derived from a password (PBKDF2).
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message
Required!;encryptedMessage</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// </remarks>
public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");
https://riptutorial.com/it/home 220
var cipherText = Convert.FromBase64String(encryptedMessage);
var plainText = SimpleDecryptWithPassword(cipherText, password, nonSecretPayloadLength);
return plainText == null ? null : Encoding.UTF8.GetString(plainText);
}
byte[] cipherText;
byte[] iv;
//Use random IV
aes.GenerateIV();
iv = aes.IV;
cipherText = cipherStream.ToArray();
}
https://riptutorial.com/it/home 221
{
//Prepend non-secret payload if any
binaryWriter.Write(nonSecretPayload);
//Prepend IV
binaryWriter.Write(iv);
//Write Ciphertext
binaryWriter.Write(cipherText);
binaryWriter.Flush();
https://riptutorial.com/it/home 222
{
KeySize = KeyBitSize,
BlockSize = BlockBitSize,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
})
{
byte[] cryptKey;
byte[] authKey;
//Use Random Salt to prevent pre-generated weak password attacks.
using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
{
var salt = generator.Salt;
//Generate Keys
cryptKey = generator.GetBytes(KeyBitSize / 8);
https://riptutorial.com/it/home 223
//Create Non Secret Payload
Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
payloadIndex += salt.Length;
}
//Generate Keys
authKey = generator.GetBytes(KeyBitSize / 8);
byte[] cryptKey;
byte[] authKey;
https://riptutorial.com/it/home 224
Castello gonfiabile AES-GCM [Gist]
/*
* This work (Modern Encryption of a String C#, by James Tuley),
* identified by James Tuley, is free of known copyright restrictions.
* https://gist.github.com/4336842
* http://creativecommons.org/publicdomain/mark/1.0/
*/
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace Encryption
{
/// <summary>
/// Helper that generates a random new key on each call.
/// </summary>
/// <returns></returns>
public static byte[] NewKey()
{
var key = new byte[KeyBitSize / 8];
Random.NextBytes(key);
return key;
}
/// <summary>
/// Simple Encryption And Authentication (AES-GCM) of a UTF8 string.
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="key">The key.</param>
/// <param name="nonSecretPayload">Optional non-secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Secret Message
Required!;secretMessage</exception>
/// <remarks>
/// Adds overhead of (Optional-Payload + BlockSize(16) + Message + HMac-Tag(16)) * 1.33
Base64
https://riptutorial.com/it/home 225
/// </remarks>
public static string SimpleEncrypt(string secretMessage, byte[] key, byte[]
nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
/// <summary>
/// Simple Decryption & Authentication (AES-GCM) of a UTF8 Message
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="key">The key.</param>
/// <param name="nonSecretPayloadLength">Length of the optional non-secret
payload.</param>
/// <returns>Decrypted Message</returns>
public static string SimpleDecrypt(string encryptedMessage, byte[] key, int
nonSecretPayloadLength = 0)
{
if (string.IsNullOrEmpty(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");
/// <summary>
/// Simple Encryption And Authentication (AES-GCM) of a UTF8 String
/// using key derived from a password (PBKDF2).
/// </summary>
/// <param name="secretMessage">The secret message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayload">The non secret payload.</param>
/// <returns>
/// Encrypted Message
/// </returns>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// Adds additional non secret payload for key generation parameters.
/// </remarks>
public static string SimpleEncryptWithPassword(string secretMessage, string password,
byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(secretMessage))
throw new ArgumentException("Secret Message Required!", "secretMessage");
/// <summary>
/// Simple Decryption and Authentication (AES-GCM) of a UTF8 message
/// using a key derived from a password (PBKDF2)
https://riptutorial.com/it/home 226
/// </summary>
/// <param name="encryptedMessage">The encrypted message.</param>
/// <param name="password">The password.</param>
/// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
/// <returns>
/// Decrypted Message
/// </returns>
/// <exception cref="System.ArgumentException">Encrypted Message
Required!;encryptedMessage</exception>
/// <remarks>
/// Significantly less secure than using random binary keys.
/// </remarks>
public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
int nonSecretPayloadLength = 0)
{
if (string.IsNullOrWhiteSpace(encryptedMessage))
throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");
//Assemble Message
using (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
//Prepend Authenticated Payload
binaryWriter.Write(nonSecretPayload);
//Prepend Nonce
binaryWriter.Write(nonce);
//Write Cipher Text
https://riptutorial.com/it/home 227
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}
//Grab Nonce
var nonce = cipherReader.ReadBytes(NonceBitSize / 8);
try
{
var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
cipher.DoFinal(plainText, len);
}
catch (InvalidCipherTextException)
{
//Return null if it doesn't authenticate
return null;
}
return plainText;
}
https://riptutorial.com/it/home 228
characters!", MinPasswordLength), "password");
generator.Init(
PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
salt,
Iterations);
//Generate Key
var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);
generator.Init(
PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
salt,
Iterations);
//Generate Key
var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);
https://riptutorial.com/it/home 229
È possibile migliorare la sicurezza per il transito o l'archiviazione dei dati implementando tecniche
di crittografia. Fondamentalmente ci sono due approcci quando si utilizza
System.Security.Cryptography : simmetrica e asimmetrica.
Crittografia simmetrica
Questo metodo utilizza una chiave privata per eseguire la trasformazione dei dati.
Professionisti:
• Gli algoritmi simmetrici consumano meno risorse e sono più veloci di quelli asimmetrici.
• La quantità di dati che puoi crittografare è illimitata.
Contro:
Crittografia asimmetrica
Questo metodo utilizza una combinazione di chiavi pubbliche e private per eseguire la
trasformazione dei dati.
Professionisti:
• Utilizza chiavi più grandi di algoritmi simmetrici, quindi sono meno suscettibili di essere
fessurate usando la forza bruta.
• È più facile garantire chi è in grado di crittografare e decrittografare i dati perché si basa su
due chiavi (pubbliche e private).
Contro:
• Esiste un limite alla quantità di dati che è possibile crittografare. Il limite è diverso per
ciascun algoritmo ed è in genere proporzionale alla dimensione della chiave dell'algoritmo.
https://riptutorial.com/it/home 230
Ad esempio, un oggetto RSACryptoServiceProvider con una lunghezza chiave di 1.024 bit
può solo crittografare un messaggio inferiore a 128 byte.
• Gli algoritmi asimmetrici sono molto lenti rispetto agli algoritmi simmetrici.
Hash password
Le password non dovrebbero mai essere archiviate come testo normale! Dovrebbero essere
sottoposti a hash con un sale generato in modo casuale (per difendersi dagli attacchi del rainbow
table) usando un algoritmo di hashing della password lenta. Un elevato numero di iterazioni (>
10k) può essere utilizzato per rallentare gli attacchi di forza bruta. Un ritardo di ~ 100 ms è
accettabile per un utente che accede, ma rende difficile rompere una password lunga. Quando si
sceglie un numero di iterazioni, è necessario utilizzare il valore massimo tollerabile per la propria
applicazione e aumentarlo man mano che le prestazioni del computer migliorano. Dovrai inoltre
considerare l'interruzione di richieste ripetute che potrebbero essere utilizzate come attacco DoS.
Quando si hashing per la prima volta che un sale può essere generato per te, il hash e il sale
risultanti possono quindi essere memorizzati in un file.
Verifica la password di un utente esistente, leggi il suo hash e il sale da un file e confronta con
l'hash della password inserita
https://riptutorial.com/it/home 231
Nell'esempio di codice seguente viene illustrato un metodo rapido e semplice per crittografare e
decodificare i file utilizzando l'algoritmo di crittografia simmetrica AES.
Il codice genera in modo casuale i vettori Salt e Initialization ogni volta che un file viene
crittografato, il che significa che la crittografia dello stesso file con la stessa password porterà
sempre a output diversi. Il sale e IV vengono scritti nel file di output in modo che solo la password
è necessaria per decrittografarlo.
public static void ProcessFile(string inputPath, string password, bool encryptMode, string
outputPath)
{
using (var cypher = new AesManaged())
using (var fsIn = new FileStream(inputPath, FileMode.Open))
using (var fsOut = new FileStream(outputPath, FileMode.Create))
{
const int saltLength = 256;
var salt = new byte[saltLength];
var iv = new byte[cypher.BlockSize / 8];
if (encryptMode)
{
// Generate random salt and IV, then write them to file
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(salt);
rng.GetBytes(iv);
}
fsOut.Write(salt, 0, salt.Length);
fsOut.Write(iv, 0, iv.Length);
}
else
{
// Read the salt and IV from the file
fsIn.Read(salt, 0, saltLength);
fsIn.Read(iv, 0, iv.Length);
}
Ci sono volte in cui la classe Random () del framework non può essere considerata abbastanza
casuale, dato che si basa su un generatore di numeri psuedo-random. Le classi Crypto del
framework, tuttavia, forniscono qualcosa di più robusto sotto forma di RNGCryptoServiceProvider.
https://riptutorial.com/it/home 232
I seguenti esempi di codice dimostrano come generare array, stringhe e numeri di byte
crittograficamente sicuri.
Stringa casuale
https://riptutorial.com/it/home 233
crittografia asimmetrica di file, soprattutto di grandi dimensioni, può spesso essere un processo
molto intensivo dal punto di vista computazionale.
Per fornire sicurezza e prestazioni, è possibile adottare un approccio ibrido. Ciò comporta la
generazione crittograficamente casuale di un vettore di chiave e di inizializzazione per la
crittografia simmetrica . Questi valori vengono quindi crittografati utilizzando un algoritmo
asimmetrico e scritti nel file di output, prima di essere utilizzati per crittografare i dati di origine in
modo simmetrico e aggiungerli all'output.
Questo approccio fornisce un alto grado di prestazioni e sicurezza, in quanto i dati vengono
crittografati utilizzando un algoritmo simmetrico (veloce) e la chiave e iv, entrambi generati
casualmente (sicuri) sono crittografati da un algoritmo asimmetrico (sicuro). Ha anche il vantaggio
aggiunto che lo stesso payload crittografato in diverse occasioni avrà un testo cifrato molto
diverso, poiché le chiavi simmetriche vengono generate casualmente ogni volta.
La seguente classe dimostra la crittografia asimmetrica di stringhe e array di byte, oltre alla
crittografia ibrida dei file.
#endregion
https://riptutorial.com/it/home 234
if (asymmetricProvider.PublicOnly)
throw new Exception("The key provided is a public key and does not contain the
private key elements required for decryption");
return asymmetricProvider.Decrypt(data, true);
}
}
#endregion
// Symmetrically encrypt the data and write it to the file, along with the
encrypted key and iv
using (var cypherKey = symmetricCypher.CreateEncryptor(key, iv))
using (var fsIn = new FileStream(inputFilePath, FileMode.Open))
using (var fsOut = new FileStream(outputFilePath, FileMode.Create))
using (var cs = new CryptoStream(fsOut, cypherKey, CryptoStreamMode.Write))
{
fsOut.Write(bufLen,0, bufLen.Length);
fsOut.Write(buf, 0, buf.Length);
fsIn.CopyTo(cs);
}
}
}
https://riptutorial.com/it/home 235
using (var symmetricCypher = new AesManaged())
using (var fsIn = new FileStream(inputFilePath, FileMode.Open))
{
// Determine the length of the encrypted key and IV
var buf = new byte[sizeof(int)];
fsIn.Read(buf, 0, buf.Length);
var bufLen = BitConverter.ToInt32(buf, 0);
// Read the encrypted key and IV data from the file and decrypt using the
asymmetric algorithm
buf = new byte[bufLen];
fsIn.Read(buf, 0, buf.Length);
buf = DecryptData(buf, privateKey);
#endregion
https://riptutorial.com/it/home 236
return srDecrypt.ReadToEnd();
}
}
}
#endregion
}
Esempio di utilizzo:
if (!File.Exists(privateKeyPath))
{
var keys = AsymmetricProvider.GenerateNewKeyPair(2048);
AsymmetricProvider.WritePublicKey(publicKeyPath, keys.PublicKey);
AsymmetricProvider.WritePrivateKey(privateKeyPath, keys.PrivateKey,
privateKeyPassword);
}
if (source.Length != dest.Length)
https://riptutorial.com/it/home 237
throw new Exception("Length does not match");
https://riptutorial.com/it/home 238
Capitolo 41: Cronometri
Sintassi
• stopWatch.Start () - Avvia il cronometro.
• stopWatch.Stop () - Interrompe il cronometro.
• stopWatch.Elapsed - Ottiene il tempo trascorso totale misurato dall'intervallo corrente.
Osservazioni
I cronometri vengono spesso utilizzati nei programmi di benchmarking per il time code e vengono
visualizzati i diversi segmenti di codice ottimali da eseguire.
Examples
Creazione di un'istanza di un cronometro
Un'istanza di cronometro può misurare il tempo trascorso su più intervalli con il tempo trascorso
totale, essendo tutti gli intervalli individuali sommati tra loro. Ciò fornisce un metodo affidabile per
misurare il tempo trascorso tra due o più eventi.
double d = 0;
for (int i = 0; i < 1000 * 1000 * 1000; i++)
{
d += 1;
}
stopWatch.Stop();
Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss\\.fffffff}", stopWatch.Elapsed);
IsHighResolution
https://riptutorial.com/it/home 239
}
else
{
Console.WriteLine("Operations timed using the DateTime class.");
}
https://dotnetfiddle.net/ckrWUo
Il timer utilizzato dalla classe Cronometro dipende dall'hardware del sistema e dal sistema
operativo. IsHighResolution è true se il timer del cronometro è basato su un contatore di
prestazioni ad alta risoluzione. In caso contrario, IsHighResolution è false, il che indica che il timer
del cronometro è basato sul timer di sistema.
Le zecche in Cronometro dipendono dalla macchina / dal sistema operativo, quindi non si
dovrebbe mai contare sulla razione di zecche del cronometro in secondi per essere uguali tra due
sistemi, e possibilmente anche sullo stesso sistema dopo un riavvio. Pertanto, non puoi mai
contare sui tick di Cronometro per avere lo stesso intervallo dei tick DateTime / TimeSpan.
Per ottenere l'ora indipendente dal sistema, assicurati di utilizzare le proprietà Cronometro
esaurite o Trascorse di millisecondi, che tengono già conto del Cronometro. Frequenza (zecche al
secondo).
fonte
https://riptutorial.com/it/home 240
Capitolo 42: Diagnostica
Examples
Debug.WriteLine
Scrive sui listener della traccia nella raccolta Listeners quando l'applicazione viene compilata in
configurazione di debug.
In Visual Studio o Xamarin Studio questo apparirà nella finestra Output dell'applicazione. Ciò è
dovuto alla presenza del listener di traccia predefinito in TraceListenerCollection.
myWriter.Flush();
}
È possibile reindirizzare l'output di debug allo stream di un'applicazione di una console utilizzando
un ConsoleTraceListener.
https://riptutorial.com/it/home 241
Capitolo 43: Dichiarazioni condizionali
Examples
Istruzione If-Else
La programmazione in generale richiede spesso una decision o una branch all'interno del codice
per tenere conto di come il codice opera in presenza di input o condizioni differenti. All'interno del
linguaggio di programmazione C # (e della maggior parte dei linguaggi di programmazione per
questo argomento), il modo più semplice e talvolta più utile di creare un ramo all'interno del
programma è attraverso un'istruzione If-Else .
Supponiamo di avere un metodo (ovvero una funzione) che accetta un parametro int che
rappresenterà un punteggio fino a 100, e il metodo stamperà un messaggio che dice se passiamo
o meno.
Osservando questo metodo, si può notare questa linea di codice ( score >= 50 ) all'interno
dell'istruzione If . Questo può essere visto come una condizione boolean , dove se la condizione
viene valutata uguale a true , allora viene eseguito il codice che si trova tra if { } .
Tuttavia, se il metodo è stato chiamato come: PrintPassOrFail(30); , l'output del metodo verrebbe
stampato dicendo Fail! . Questo perché il valore 30 non è maggiore o uguale a 50, quindi viene
eseguito il codice tra else { } anziché l'istruzione If .
In questo esempio, abbiamo detto che il punteggio dovrebbe arrivare a 100, che non è stato
affatto calcolato. Per tenere conto del punteggio che non va oltre il 100 o eventualmente scendere
al di sotto di 0, vedere l'esempio dell'istruzione If-Else If-Else .
https://riptutorial.com/it/home 242
intrinsecamente ha una sintassi simile all'istruzione If . È usato per aggiungere più rami al codice
di quello che può fare una semplice istruzione If-Else .
Nell'esempio di If-Else Statement , l'esempio ha specificato che il punteggio sale a 100; tuttavia
non ci sono mai stati controlli contro questo. Per risolvere questo problema, è possibile modificare
il metodo dall'istruzione If-Else in modo che assomigli a questo:
Tutte queste affermazioni funzioneranno in ordine dall'alto verso il basso fino a quando una
condizione non sarà soddisfatta. In questo nuovo aggiornamento del metodo, abbiamo aggiunto
due nuovi rami per ospitare ora il punteggio in uscita .
Ad esempio, se ora chiamiamo il metodo nel nostro codice come PrintPassOFail(110); , l'output
sarebbe una stampa della console che dice Errore: il punteggio è maggiore di 100! ; e se
abbiamo chiamato il metodo nel nostro codice come PrintPassOrFail(-20); , l'output direbbe
Errore: il punteggio è inferiore a 0! .
Cambia istruzioni
Un'istruzione switch consente di verificare una variabile per l'uguaglianza rispetto a un elenco di
valori. Ogni valore è chiamato caso e la variabile che viene attivata viene controllata per ogni caso
di commutazione.
Un'istruzione switch è spesso più concisa e comprensibile rispetto a if...else if... else..
istruzioni quando si testano più valori possibili per una singola variabile.
La sintassi è la seguente
switch(expression) {
case constant-expression:
statement(s);
break;
case constant-expression:
statement(s);
https://riptutorial.com/it/home 243
break;
ci sono cose settarie che devono essere considerate mentre si usa l'istruzione switch
switch (grade)
{
case 'A':
Console.WriteLine("Excellent!");
break;
case 'B':
case 'C':
Console.WriteLine("Well done");
break;
case 'D':
Console.WriteLine("You passed");
break;
case 'F':
Console.WriteLine("Better try again");
break;
default:
Console.WriteLine("Invalid grade");
break;
}
La seguente dichiarazione
è esattamente equivalente a
https://riptutorial.com/it/home 244
bool conditions = conditionA && conditionB && conditionC;
if (conditions) // ...
https://riptutorial.com/it/home 245
Capitolo 44: Direttive preprocessore
Sintassi
• #define [symbol] // Definisce un simbolo del compilatore.
• #undef [symbol] // Undefines un simbolo del compilatore.
• #warning [messaggio di avviso] // Genera un avvertimento del compilatore. Utile con #if.
• #error [messaggio di errore] // Genera un errore del compilatore. Utile con #if.
• #line [numero linea] (nome file) // Sovrascrive il numero di riga del compilatore (e
facoltativamente il nome del file sorgente). Utilizzato con modelli di testo T4 .
• #pragma warning [disable | restore] [warning numbers] // Disabilita / ripristina gli avvisi del
compilatore.
• #pragma checksum " [nomefile] " " [guid] " " [checksum] " // Convalida il contenuto di un file
sorgente.
• #region [nome regione] // Definisce una regione di codice comprimibile.
• #endregion // Termina un blocco dell'area del codice.
• #if [condizione] // Esegue il codice qui sotto se la condizione è vera.
• #else // Utilizzato dopo un #if.
• #elif [condizione] // Utilizzato dopo un #if.
• #endif // Termina un blocco condizionale avviato con #if.
Osservazioni
Le direttive del preprocessore sono generalmente utilizzate per rendere i programmi di origine
facili da modificare e facili da compilare in diversi ambienti di esecuzione. Le direttive nel file
sorgente indicano al preprocessore di eseguire azioni specifiche. Ad esempio, il preprocessore
può sostituire i token nel testo, inserire il contenuto di altri file nel file sorgente o sopprimere la
compilazione di parte del file rimuovendo sezioni di testo. Le linee del preprocessore vengono
riconosciute e eseguite prima dell'espansione macro. Pertanto, se una macro si espande in
qualcosa che assomiglia a un comando del preprocessore, tale comando non viene riconosciuto
dal preprocessore.
Le istruzioni di preprocessore utilizzano lo stesso set di caratteri delle istruzioni del file di origine,
con l'eccezione che le sequenze di escape non sono supportate. Il set di caratteri utilizzato nelle
istruzioni del preprocessore è uguale al set di caratteri di esecuzione. Il preprocessore riconosce
anche i valori dei caratteri negativi.
Espressioni condizionali
Le espressioni condizionali ( #if , #elif , ecc.) Supportano un sottoinsieme limitato di operatori
booleani. Loro sono:
• == e != . Questi possono essere utilizzati solo per verificare se il simbolo è vero (definito) o
falso (non definito)
• &&
https://riptutorial.com/it/home 246
, || , !
• ()
Per esempio:
compilerebbe il codice che stampa "OK!" alla console se DEBUG non è definito, sono definiti
SOME_SYMBOL o SOME_OTHER_SYMBOL e RELEASE è definito.
Nota: queste sostituzioni vengono eseguite in fase di compilazione e pertanto non sono disponibili
per l'ispezione in fase di esecuzione. Il codice eliminato tramite l'uso di #if non fa parte dell'output
del compilatore.
Examples
Espressioni condizionali
Quando viene compilato quanto segue, verrà restituito un valore diverso a seconda delle direttive
definite.
Le espressioni condizionali vengono in genere utilizzate per registrare informazioni aggiuntive per
le build di debug.
void SomeFunc()
{
try
{
SomeRiskyMethod();
}
catch (ArgumentException ex)
{
#if DEBUG
log.Error("SomeFunc", ex);
#endif
HandleException(ex);
https://riptutorial.com/it/home 247
}
}
Gli avvertimenti del compilatore possono essere generati usando la direttiva #warning e gli errori
possono essere generati anche usando la direttiva #error .
#if SOME_SYMBOL
#error This is a compiler Error.
#elif SOME_OTHER_SYMBOL
#warning This is a compiler Warning.
#endif
Un simbolo del compilatore è una parola chiave definita in fase di compilazione che può essere
controllata per eseguire in modo condizionato specifiche sezioni di codice.
Esistono tre modi per definire un simbolo del compilatore. Possono essere definiti tramite codice:
#define MYSYMBOL
Possono essere definiti in Visual Studio, in Proprietà progetto> Crea> Simboli di compilazione
condizionale:
(Si noti che DEBUG e TRACE hanno le proprie caselle di controllo e non è necessario specificare
esplicitamente.)
Oppure possono essere definiti in fase di compilazione usando l' csc.exe /define:[name] sul
compilatore C #, csc.exe .
L'esempio più diffuso di questo è il simbolo DEBUG , che viene definito da Visual Studio quando
un'applicazione viene compilata in modalità Debug (rispetto alla modalità di rilascio).
https://riptutorial.com/it/home 248
public void DoBusinessLogic()
{
try
{
AuthenticateUser();
LoadAccount();
ProcessAccount();
FinalizeTransaction();
}
catch (Exception ex)
{
#if DEBUG
System.Diagnostics.Trace.WriteLine("Unhandled exception!");
System.Diagnostics.Trace.WriteLine(ex);
throw;
#else
LoggingFramework.LogError(ex);
DisplayFriendlyErrorMessage();
#endif
}
}
Blocchi Regionali
#endregion
Queste direttive sono utili solo quando un IDE che supporta regioni comprimibili (come Visual
Studio ) viene utilizzato per modificare il codice.
Linea
https://riptutorial.com/it/home 249
#line controlla il numero di riga e il nome del file riportati dal compilatore durante l'emissione di
avvisi ed errori.
void Test()
{
#line 42 "Answer"
#line filename "SomeFile.cs"
int life; // compiler warning CS0168 in "SomeFile.cs" at Line 42
#line default
// compiler warnings reset to default
}
Checksum di Pragma
consente la specifica di un checksum specifico per un database di programma
#pragma checksum
generato (PDB) per il debug.
#define EXAMPLE_A
using System.Diagnostics;
class Program
{
static void Main()
{
ExampleA(); // This method will be called
ExampleB(); // This method will not be called
}
[Conditional("EXAMPLE_A")]
static void ExampleA() {...}
[Conditional("EXAMPLE_B")]
static void ExampleB() {...}
}
È possibile disabilitare gli avvisi del compilatore utilizzando l' #pragma warning disable e ripristinarli
utilizzando il #pragma warning restore :
// Will not generate the "unused variable" compiler warning since it was disabled
var x = 5;
https://riptutorial.com/it/home 250
#pragma warning restore CS0168
// Will generate a compiler warning since the warning was just restored
var y = 8;
Il prefisso CS è facoltativo e può anche essere mescolato (anche se questa non è una best
practice):
Vai a Solution Explorer -> Fai clic con il pulsante destro del mouse sul progetto per cui vuoi
impostare la variabile su -> Properties -> Build -> Nel campo di ricerca Generale Conditional
compilation symbols e inserisci qui la variabile condizionale
https://riptutorial.com/it/home 251
Esempio di codice che salterà del codice:
https://riptutorial.com/it/home 252
Capitolo 45: enum
introduzione
Un enum può derivare da uno dei seguenti tipi: byte, sbyte, short, ushort, int, uint, long, ulong. Il
valore predefinito è int e può essere modificato specificando il tipo nella definizione enum:
Questo è utile quando P / Invoca codice nativo, mappatura a origini dati e circostanze simili. In
generale, si dovrebbe usare l'int predefinito, perché la maggior parte degli sviluppatori si aspetta
che un enum sia int.
Sintassi
• enum Colors {Red, Green, Blue} // Dichiarazione Enum
• enum Colori: byte {rosso, verde, blu} // Dichiarazione con tipo specifico
• enum Colors {Red = 23, Green = 45, Blue = 12} // Dichiarazione con valori definiti
• Colors.Red // Accede a un elemento di un Enum
• int value = (int) Colors.Red // Ottieni il valore int di un elemento enum
• Colors color = (Colors) intValue // Ottieni un elemento enum da int
Osservazioni
Un enum (abbreviazione di "tipo enumerato") è un tipo costituito da un insieme di costanti
nominate, rappresentate da un identificatore specifico del tipo.
Le enumerazioni sono più utili per rappresentare concetti che hanno un numero (solitamente
piccolo) di valori discreti possibili. Ad esempio, possono essere utilizzati per rappresentare un
giorno della settimana o un mese dell'anno. Possono anche essere usati come flag che possono
essere combinati o controllati, usando operazioni bit a bit.
Examples
Ottieni tutti i valori dei membri di un enum
enum MyEnum
{
One,
Two,
Three
}
foreach(MyEnum e in Enum.GetValues(typeof(MyEnum)))
Console.WriteLine(e);
https://riptutorial.com/it/home 253
Questo stamperà:
One
Two
Three
[Flags]
enum MyEnum
{
//None = 0, can be used but not combined in bitwise operations
FlagA = 1,
FlagB = 2,
FlagC = 4,
FlagD = 8
//you must use powers of two or combinations of powers of two
//for bitwise operations to work
}
// This will enumerate all the flags in the variable: "FlagA, FlagB".
Console.WriteLine(twoFlags);
Poiché FlagsAttribute si basa sulle costanti di enumerazione per essere poteri di due (o le loro
combinazioni) ei valori enum sono in definitiva valori numerici, si è limitati dalla dimensione del
tipo numerico sottostante. Il più grande tipo numerico disponibile che è possibile utilizzare è UInt64
, che consente di specificare 64 costanti enum flag distinte (non combinate). La parola chiave enum
imposta automaticamente il tipo sottostante int , che è Int32 . Il compilatore consentirà la
dichiarazione di valori più ampi di 32 bit. Quelli si avvolgeranno senza avviso e generano due o
più membri enum dello stesso valore. Pertanto, se un enum è pensato per contenere un set di bit
di oltre 32 flag, è necessario specificare esplicitamente un tipo più grande:
Sebbene i flag siano spesso solo un singolo bit, possono essere combinati in "set" denominati per
un utilizzo più semplice.
[Flags]
enum FlagsEnum
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
https://riptutorial.com/it/home 254
Default = Option1 | Option3,
All = Option1 | Option2 | Option3,
}
Per evitare di compitare i valori decimali delle potenze di due, l' operatore di spostamento a
sinistra (<<) può anche essere usato per dichiarare lo stesso enum
[Flags]
enum FlagsEnum
{
None = 0,
Option1 = 1 << 0,
Option2 = 1 << 1,
Option3 = 1 << 2,
Per verificare se il valore della variabile enum ha un determinato flag impostato, è possibile
utilizzare il metodo HasFlag . Diciamo che abbiamo
[Flags]
enum MyEnum
{
One = 1,
Two = 2,
Three = 4
}
E un value
if(value.HasFlag(MyEnum.One))
Console.WriteLine("Enum has One");
if(value.HasFlag(MyEnum.Two))
Console.WriteLine("Enum has Two");
if(value.HasFlag(MyEnum.Three))
Console.WriteLine("Enum has Three");
Inoltre possiamo scorrere tutti i valori di enum per ottenere tutti i flag impostati
https://riptutorial.com/it/home 255
var item = (MyEnum)Enum.Parse(type, name);
if (value.HasFlag(item))
Console.WriteLine("Enum has " + name);
}
Un valore enum in stile flags deve essere testato con logica bit a bit perché potrebbe non
corrispondere a nessun singolo valore.
[Flags]
enum FlagsEnum
{
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option2And3 = Option2 | Option3;
Il valore Default è in realtà una combinazione di altri due uniti con un OR bit a bit. Quindi per
testare la presenza di un flag dobbiamo usare un AND bit a bit.
Assert.True(isOption2And3Set);
https://riptutorial.com/it/home 256
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
// Enum to string
string thursday = DayOfWeek.Thursday.ToString(); // "Thursday"
// String to enum (.NET 4.0+ only - see below for alternative syntax for earlier .NET
versions)
DayOfWeek tuesday;
Enum.TryParse("Tuesday", out tuesday); // DayOfWeek.Tuesday
DayOfWeek sunday;
bool matchFound1 = Enum.TryParse("SUNDAY", out sunday); // Returns false (case-sensitive
match)
DayOfWeek wednesday;
bool matchFound2 = Enum.TryParse("WEDNESDAY", true, out wednesday); // Returns true;
DayOfWeek.Wednesday (case-insensitive match)
Il valore predefinito per un enum è zero . Se un enum non definisce un oggetto con un valore
pari a zero, il suo valore predefinito sarà zero.
if (e == EnumExample.one)
Console.WriteLine("defaults to one");
else
https://riptutorial.com/it/home 257
Console.WriteLine("Unknown");
}
}
Esempio: https://dotnetfiddle.net/l5Rwie
Da MSDN :
Essenzialmente, un enum è un tipo che consente solo un insieme di opzioni finite e ogni opzione
corrisponde a un numero. Per impostazione predefinita, tali numeri aumentano nell'ordine in cui i
valori sono dichiarati, a partire da zero. Ad esempio, si potrebbe dichiarare un enum per i giorni
della settimana:
Per impostazione predefinita, il tipo sottostante di ciascun elemento enum è int , ma possono
essere utilizzati anche byte , sbyte , short , ushort , uint , long e ulong . Se si utilizza un tipo diverso
da int , è necessario specificare il tipo utilizzando i due punti dopo il nome dell'enumerazione:
https://riptutorial.com/it/home 258
I numeri dopo il nome ora sono byte anziché interi. È possibile ottenere il tipo sottostante
dell'enumerazione come segue:
Enum.GetUnderlyingType(typeof(Days)));
Produzione:
System.Byte
Il FlagsAttribute deve essere utilizzato ogni volta che l'enumerable rappresenta una raccolta di
flag, piuttosto che un singolo valore. Il valore numerico assegnato a ciascun valore enumerato
aiuta a manipolare le enumerazioni utilizzando operatori bit a bit.
[Flags]
enum Colors
{
Red=1,
Blue=2,
Green=4,
Yellow=8
}
enum Colors
{
Red=1,
Blue=2,
Green=4,
Yellow=8
}
var color = Colors.Red | Colors.Blue;
Console.WriteLine(color.ToString());
stampa 3
L'operatore di spostamento a sinistra ( << ) può essere utilizzato nelle dichiarazioni flag enum per
garantire che ogni flag abbia esattamente un 1 nella rappresentazione binaria, come dovrebbero
https://riptutorial.com/it/home 259
essere le bandiere.
Questo aiuta anche a migliorare la leggibilità di enumerazioni di grandi dimensioni con un sacco di
bandiere in esse.
[Flags]
public enum MyEnum
{
None = 0,
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2,
Flag4 = 1 << 3,
Flag5 = 1 << 4,
...
Flag31 = 1 << 30
}
Ora è ovvio che MyEnum contiene solo flag appropriati e non roba disordinata come Flag30 =
1073741822 (o 1111111111111111111111111111111110 in binario) che è inappropriato.
In alcuni casi è possibile aggiungere una descrizione aggiuntiva a un valore enum, ad esempio
quando il valore enum è meno leggibile di quello che si potrebbe desiderare di visualizzare
all'utente. In questi casi è possibile utilizzare la classe System.ComponentModel.DescriptionAttribute .
Per esempio:
Ora, se vuoi restituire la descrizione di un valore enum specifico, puoi fare quanto segue:
https://riptutorial.com/it/home 260
Questo può anche essere facilmente trasformato in un metodo di estensione per tutte le
enumerazioni:
[Flags]
public enum MyEnum
{
Flag1 = 1 << 0,
Flag2 = 1 << 1,
Flag3 = 1 << 2
}
// remove flag
value &= ~MyEnum.Flag2; //value is now Flag1, Flag3
Poiché un enum può essere lanciato su e dal suo tipo integrale sottostante, il valore potrebbe non
rientrare nell'intervallo di valori indicato nella definizione del tipo enum.
Sebbene il tipo di DaysOfWeek seguente DaysOfWeek abbia solo 7 valori definiti, può comunque
contenere qualsiasi valore int .
https://riptutorial.com/it/home 261
DaysOfWeek d = (DaysOfWeek)31;
Console.WriteLine(d); // prints 31
DaysOFWeek s = DaysOfWeek.Sunday;
s++; // No error
Attualmente non esiste un modo per definire un enum che non abbia questo comportamento.
Tuttavia, i valori di enum non definiti possono essere rilevati utilizzando il metodo Enum.IsDefined .
Per esempio,
DaysOfWeek d = (DaysOfWeek)31;
Console.WriteLine(Enum.IsDefined(typeof(DaysOfWeek),d)); // prints False
https://riptutorial.com/it/home 262
Capitolo 46: Eredità
Sintassi
• class DerivedClass: BaseClass
• class DerivedClass: BaseClass, IExampleInterface
• class DerivedClass: BaseClass, IExampleInterface, IAnotherInterface
Osservazioni
Le classi possono ereditare direttamente da una sola classe, ma (al suo posto o allo stesso
tempo) possono implementare una o più interfacce.
Examples
Ereditare da una classe base
Per evitare la duplicazione del codice, definire i metodi e gli attributi comuni in una classe generale
come base:
Ora che hai una classe che rappresenta Animal in generale, puoi definire una classe che descrive
le peculiarità di specifici animali:
https://riptutorial.com/it/home 263
{
public Cat()
{
Name = "Cat";
}
// Methods for scratching furniture and ignoring owner
public void Scratch(Object furniture)
{
// ...
}
}
La classe Cat accede non solo ai metodi descritti nella sua definizione in modo esplicito, ma
anche a tutti i metodi definiti nella classe generale Animal base. Qualsiasi animale (che fosse o
meno un gatto) poteva mangiare, stare in piedi o rotolare. Un animale non sarebbe in grado di
grattare, tuttavia, a meno che non fosse anche un gatto. Potresti quindi definire altre classi che
descrivono altri animali. (Come Gopher con un metodo per distruggere i giardini fioriti e la bradipo
senza alcun metodo aggiuntivo.)
//Note that in C#, the base class name must come before the interface names
public class Cat : Animal, INoiseMaker
{
public Cat()
{
Name = "Cat";
}
https://riptutorial.com/it/home 264
}
//Note that in C#, the base class name must come before the interface names
public class Cat : LivingBeing, IAnimal, INoiseMaker
{
public Cat()
{
Name = "Cat";
HasHair = true;
}
interface BaseInterface {}
class BaseClass : BaseInterface {}
interface DerivedInterface {}
class DerivedClass : BaseClass, DerivedInterface {}
Console.WriteLine(derivedType.BaseType.Name); //BaseClass
Console.WriteLine(baseType.BaseType.Name); //Object
Console.WriteLine(typeof(object).BaseType); //null
Console.WriteLine(baseType.IsInstanceOfType(derivedInstance)); //True
Console.WriteLine(derivedType.IsInstanceOfType(baseInstance)); //False
Console.WriteLine(
string.Join(",",
derivedType.GetInterfaces().Select(t => t.Name).ToArray()));
//BaseInterface,DerivedInterface
https://riptutorial.com/it/home 265
Console.WriteLine(baseInterfaceType.IsAssignableFrom(derivedType)); //True
Console.WriteLine(derivedInterfaceType.IsAssignableFrom(derivedType)); //True
Console.WriteLine(derivedInterfaceType.IsAssignableFrom(baseType)); //False
A differenza delle interfacce, che possono essere descritte come contratti per l'implementazione,
le classi astratte fungono da contratti per l'estensione.
Una classe astratta non può essere istanziata, deve essere estesa e la classe risultante (o classe
derivata) può quindi essere istanziata.
L'esempio sopra mostra come qualsiasi classe che estende l'auto riceverà automaticamente il
metodo HonkHorn con l'implementazione. Ciò significa che qualsiasi sviluppatore che crea una
nuova auto non dovrà preoccuparsi di come suonerà il clacson.
Quando crei una sottoclasse di una classe base, puoi costruire la classe base usando : base dopo
i parametri del costruttore della sottoclasse.
class Instrument
{
string type;
bool clean;
https://riptutorial.com/it/home 266
public Trumpet(string type, bool clean, bool oiled) : base(type, clean)
{
this.oiled = oiled;
}
}
class Animal
{
public Animal()
{
Console.WriteLine("In Animal's constructor");
}
}
Quando si crea un'istanza della classe Dog , il costruttore predefinito delle classi base (senza
parametri) verrà chiamato se non vi è alcuna chiamata esplicita a un altro costruttore nella
classe genitore . Nel nostro caso, prima si chiamerà Object's constructor, quindi Animal's e alla
fine Dog's costruttore Dog's .
L'output sarà
https://riptutorial.com/it/home 267
Nel costruttore di Dog
Visualizza la demo
Negli esempi precedenti, il nostro costruttore di classi Dog chiama il costruttore predefinito della
classe Animal . Se vuoi, puoi specificare quale costruttore dovrebbe essere chiamato: è possibile
chiamare qualsiasi costruttore che è definito nella classe genitore.
class Animal
{
protected string name;
public Animal()
{
Console.WriteLine("Animal's default constructor");
}
base è un riferimento alla classe genitore. Nel nostro caso, quando creiamo un'istanza di classe
Dog come questa
Il runtime chiama prima Dog() , che è il costruttore senza parametri. Ma il suo corpo non funziona
https://riptutorial.com/it/home 268
immediatamente. Dopo le parentesi del costruttore abbiamo una tale chiamata: base() , il che
significa che quando chiamiamo il costruttore predefinito di Dog , a sua volta chiamerà il costruttore
predefinito del genitore. Dopo che il costruttore del genitore è stato eseguito, verrà restituito e,
infine, verrà eseguito il corpo del costruttore Dog() .
Visualizza la demo
Sapete che i membri della classe genitore che non sono privati sono ereditati dalla classe figlia,
nel senso che Dog avrà anche il campo del name .
In questo caso abbiamo passato un argomento al nostro costruttore. A sua volta passa
l'argomento al costruttore della classe genitore con un parametro , che inizializza il campo del
name .
L'output sarà
Sommario:
Ogni creazione di oggetti inizia dalla classe base. Nell'ereditarietà, le classi che si trovano nella
gerarchia sono concatenate. Poiché tutte le classi derivano da Object , il primo costruttore da
chiamare quando viene creato un oggetto è il costruttore della classe Object ; Quindi viene
chiamato il prossimo costruttore della catena e solo dopo che tutti sono chiamati viene creato
l'oggetto
1. La parola chiave di base viene utilizzata per accedere ai membri della classe base da una
classe derivata:
2. Chiama un metodo sulla classe base che è stato sovrascritto da un altro metodo. Specificare
quale costruttore della classe base deve essere chiamato quando si creano le istanze della
classe derivata.
Metodi ereditari
https://riptutorial.com/it/home 269
public abstract class Car
{
public void HonkHorn() {
// Implementation of horn being honked
}
Ereditarietà Anti-pattern
Eredità impropria
Diciamo che ci sono 2 classi di classe Foo e Bar . Foo ha due funzioni Do1 e Do2 . Bar bisogno di
usare Do1 da Foo , ma non ha bisogno di Do2 o di funzionalità che equivalgono a Do2 ma fa qualcosa
di completamente diverso.
Cattivo : crea Do2() su Foo virtual quindi sostituiscilo in Bar o throw Exception in Bar per Do2()
Buon modo
Prendi Do1() da Foo e mettilo nella nuova classe Baz poi eredita sia Foo che Bar da Baz e implementa
https://riptutorial.com/it/home 270
Do2() separatamente
Ora, perché il primo esempio è cattivo e il secondo è buono: quando lo sviluppatore nr2 deve fare
una modifica in Foo , è probabile che interromperà l'implementazione di Bar perché la Bar è ora
inseparabile da Foo . Quando lo si fa con l'ultimo esempio, Foo and Bar commonalty è stato
spostato su Baz e non si influenzano a vicenda (come il non dovrebbe).
Definizione una tantum di una classe base generica con identificatore di tipo ricorsivo. Ogni nodo
ha un genitore e più figli.
/// <summary>
/// Generic base class for a tree structure
/// </summary>
/// <typeparam name="T">The node type of the tree</typeparam>
public abstract class Tree<T> where T : Tree<T>
{
/// <summary>
/// Constructor sets the parent node and adds this node to the parent's child nodes
/// </summary>
/// <param name="parent">The parent node or null if a root</param>
protected Tree(T parent)
{
this.Parent=parent;
this.Children=new List<T>();
if(parent!=null)
{
parent.Children.Add(this as T);
}
}
public T Parent { get; private set; }
public List<T> Children { get; private set; }
https://riptutorial.com/it/home 271
public bool IsRoot { get { return Parent==null; } }
public bool IsLeaf { get { return Children.Count==0; } }
/// <summary>
/// Returns the number of hops to the root object
/// </summary>
public int Level { get { return IsRoot ? 0 : Parent.Level+1; } }
}
Quanto sopra può essere riutilizzato ogni volta che è necessario definire una gerarchia di alberi.
L'oggetto nodo nella struttura deve ereditare dalla classe base con
ogni classe nodo sa dove si trova nella gerarchia, quale sia l'oggetto genitore e gli oggetti figli.
Diversi tipi incorporati utilizzano una struttura ad albero, come Control o XmlElement e l' Tree<T>
sopra può essere usato come una classe base di qualsiasi tipo nel codice.
Ad esempio, per creare una gerarchia di parti in cui viene calcolato il peso totale dal peso di tutti i
bambini, effettuare le seguenti operazioni:
// 2.5+(4.2+0.4)+0.9 = 8.0
float weight = Q.TotalWeight;
Un altro esempio sarebbe nella definizione dei frame di coordinate relative. In questo caso, la
posizione reale del frame di coordinate dipende dalle posizioni di tutti i frame di coordinate padre.
https://riptutorial.com/it/home 272
public class RelativeCoordinate : Tree<RelativeCoordinate>
{
public static readonly RelativeCoordinate Start = new RelativeCoordinate(null,
PointF.Empty) { };
public RelativeCoordinate(RelativeCoordinate parent, PointF local_position)
: base(parent)
{
this.LocalPosition=local_position;
}
public PointF LocalPosition { get; set; }
public PointF GlobalPosition
{
get
{
if(IsRoot) return LocalPosition;
var parent_pos = Parent.GlobalPosition;
return new PointF(parent_pos.X+LocalPosition.X, parent_pos.Y+LocalPosition.Y);
}
}
public float TotalDistance
{
get
{
float dist =
(float)Math.Sqrt(LocalPosition.X*LocalPosition.X+LocalPosition.Y*LocalPosition.Y);
return IsRoot ? dist : Parent.TotalDistance+dist;
}
}
public RelativeCoordinate Add(PointF local_position)
{
return new RelativeCoordinate(this, local_position);
}
public RelativeCoordinate Add(float x, float y)
{
return Add(new PointF(x, y));
}
}
var A1 = RelativeCoordinate.Start;
var B1 = A1.Add(100, 20);
var B2 = A1.Add(160, 10);
https://riptutorial.com/it/home 273
Capitolo 47: Esecuzione di richieste HTTP
Examples
Creazione e invio di una richiesta POST HTTP
using System.Net;
using System.IO;
...
// Set the POST request body data. In this example, the POST data is in
// application/x-www-form-urlencoded format.
string postData = "myparam1=myvalue1&myparam2=myvalue2";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(postData);
}
// Submit the request, and get the response body from the remote server.
string responseFromRemoteServer;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
responseFromRemoteServer = reader.ReadToEnd();
}
}
using System.Net;
using System.IO;
...
https://riptutorial.com/it/home 274
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
responseBodyFromRemoteServer = reader.ReadToEnd();
}
}
Gestione degli errori di specifici codici di risposta HTTP (come 404 non
trovato)
using System.Net;
...
string serverResponse;
try
{
// Call a method that performs an HTTP request (per the above examples).
serverResponse = PerformHttpRequest();
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = ex.Response as HttpWebResponse;
if (response != null)
{
if ((int)response.StatusCode == 404) // Not Found
{
// Handle the 404 Not Found error
// ...
}
else
{
// Could handle other response.StatusCode values here.
// ...
}
}
}
else
{
// Could handle other error conditions here, such as
WebExceptionStatus.ConnectFailure.
// ...
}
}
https://riptutorial.com/it/home 275
}
}
. . .
if (!message.IsSuccessStatusCode)
throw new Exception();
return message.ReadAsAsync<TResult>();
}
}
. . .
Console.WriteLine(contents);
https://riptutorial.com/it/home 276
Capitolo 48: Esempi Async / Waitit,
Backgroundworker, Task e Thread
Osservazioni
Per eseguire uno di questi esempi, chiamali in questo modo:
Examples
ASP.NET Configure Await
Quando ASP.NET gestisce una richiesta, viene assegnato un thread dal pool di thread e viene
creato un contesto di richiesta . Il contesto della richiesta contiene informazioni sulla richiesta
corrente a cui è possibile accedere tramite la proprietà statica HttpContext.Current . Il contesto
della richiesta per la richiesta viene quindi assegnato al thread che gestisce la richiesta.
Un determinato contesto di richiesta può essere attivo solo su un thread alla volta .
Quando l'esecuzione giunge in await , il thread che gestisce una richiesta viene restituito al pool di
thread mentre viene eseguito il metodo asincrono e il contesto della richiesta è gratuito per un
altro thread da utilizzare.
Al termine dell'attività, il pool di thread assegna un altro thread per continuare l'esecuzione della
richiesta. Il contesto della richiesta viene quindi assegnato a questo thread. Questo potrebbe
essere o non essere il thread originale.
Blocco
Quando si attende il risultato di una chiamata al metodo async , possono verificarsi deadlock
sincroni . Ad esempio, il seguente codice genererà un deadlock quando viene chiamato
https://riptutorial.com/it/home 277
IndexSync() :
return result;
}
Quando l'intero stack di chiamate è asincrono, non ci sono problemi perché, una volta in await
viene raggiunto, il thread originale viene rilasciato, liberando il contesto della richiesta.
Quando si blocca in modo sincrono utilizzando Task.Result o Task.Wait() (o altri metodi di blocco) il
thread originale è ancora attivo e conserva il contesto della richiesta. Il metodo atteso funziona
ancora in modo asincrono e una volta che il callback tenta di essere eseguito, ovvero quando
viene restituita l'attività attesa, tenta di ottenere il contesto della richiesta.
Pertanto il deadlock si verifica perché mentre il thread di blocco con il contesto della richiesta è in
attesa del completamento dell'operazione asincrona, l'operazione asincrona sta tentando di
ottenere il contesto della richiesta per il completamento.
ConfigureAwait
Usando ConfigureAwait(false) questo può essere prevenuto e le deadlock possono essere evitate.
// Execution resumes on a "random" thread from the pool without the original request
context
return View(products);
}
https://riptutorial.com/it/home 278
public ActionResult IndexSync()
{
Task<ActionResult> task = Index();
return result;
}
Questo può evitare deadlock quando è necessario bloccare il codice asincrono, tuttavia ciò
comporta il costo di perdere il contesto nella continuazione (codice dopo la chiamata in attesa).
In ASP.NET questo significa che se il tuo codice segue una chiamata per await
someTask.ConfigureAwait(false); tenta di accedere alle informazioni dal contesto, ad esempio
HttpContext.Current.User quindi le informazioni sono state perse. In questo caso,
HttpContext.Current è null. Per esempio:
return View();
}
Se viene utilizzato ConfigureAwait(true) (equivalente a non avere affatto ConfigureAwait), sia l'
user che l' user2 vengono popolati con gli stessi dati.
Per questo motivo, si consiglia spesso di utilizzare ConfigureAwait(false) nel codice della libreria in
cui il contesto non è più utilizzato.
Async / await
Vedi sotto per un semplice esempio di come usare async / attendi di fare un po 'di tempo in un
processo in background, mantenendo l'opzione di fare altre cose che non hanno bisogno di
aspettare le cose che richiedono molto tempo per essere completate.
Tuttavia, se è necessario lavorare con il risultato del metodo intensivo in un secondo momento, è
possibile farlo attendendo l'esecuzione.
https://riptutorial.com/it/home 279
// Control returns here before TimeintensiveMethod returns
Console.WriteLine("You can read this while TimeintensiveMethod is still running.");
BackgroundWorker
Vedi sotto per un semplice esempio di come utilizzare un oggetto BackgroundWorker per eseguire
operazioni che richiedono molto tempo in un thread in background.
Devi:
Oltre all'evento DoWork , la classe BackgroundWorker definisce anche due eventi che dovrebbero
essere utilizzati per interagire con l'interfaccia utente. Questi sono opzionali.
• L'evento RunWorkerCompleted viene attivato quando i gestori DoWork sono stati completati.
• L'evento ProgressChanged viene attivato quando viene chiamato il metodo ReportProgress .
https://riptutorial.com/it/home 280
Console.WriteLine("You can read this while TimeintensiveMethod is still running.");
}
Compito
Vedi sotto per un semplice esempio di come usare un Task per fare cose che richiedono molto
tempo in un processo in background.
Tutto quello che devi fare è avvolgere il tuo metodo intensivo in una chiamata Task.Run() .
https://riptutorial.com/it/home 281
{
string s = reader.ReadToEnd();
Filo
Vedi sotto per un semplice esempio di come usare un Thread per fare cose che richiedono tempo
in un processo in background.
Come puoi vedere, non possiamo restituire un valore dal nostro TimeIntensiveMethod perché Thread
aspetta un metodo void come parametro.
int ret;
Thread t= new Thread(() =>
{
Console.WriteLine("Start TimeintensiveMethod.");
https://riptutorial.com/it/home 282
s.GetHashCode();
}
Console.WriteLine("End TimeintensiveMethod.");
t.Start();
t.Join(1000);
Console.Writeline("Count: " + ret);
In alcuni casi (ad esempio la registrazione) potrebbe essere utile eseguire l'attività e non attendere
il risultato. La seguente estensione consente di eseguire attività e continuare l'esecuzione del
codice di resto:
Il risultato è atteso solo all'interno del metodo di estensione. Poiché async / await viene utilizzato, è
possibile rilevare un'eccezione e chiamare un metodo opzionale per gestirlo.
var task = Task.FromResult(0); // Or any other task from e.g. external lib.
task.RunAndForget(
e =>
{
// Something went wrong, handle it.
});
https://riptutorial.com/it/home 283
Capitolo 49: Espressioni Lambda
Osservazioni
Un'espressione lambda è una sintassi per la creazione di funzioni anonime in linea. Più
formalmente, dalla Guida alla Programmazione C # :
Un'espressione lambda è una funzione anonima che è possibile utilizzare per creare
delegati o tipi di albero di espressioni. Utilizzando espressioni lambda, è possibile
scrivere funzioni locali che possono essere passate come argomenti o restituite come
valore delle chiamate di funzione.
Un'espressione lambda viene creata usando l'operatore => . Metti tutti i parametri sul lato sinistro
dell'operatore. Sul lato destro, metti un'espressione che può usare quei parametri; questa
espressione si risolverà come valore di ritorno della funzione. Più raramente, se necessario, un
intero {code block} può essere utilizzato sul lato destro. Se il tipo di reso non è nullo, il blocco
conterrà un'istruzione di reso.
Examples
Passare un'espressione lambda come parametro di un metodo
List<int> l2 = l1.FindAll(x => x > 6);
Qui x => x > 6 è un'espressione lambda che funge da predicato che assicura che vengano
restituiti solo gli elementi superiori a 6.
Tipicamente i lambda sono usati per definire semplici funzioni (generalmente nel contesto di
un'espressione linq):
https://riptutorial.com/it/home 284
Qui il return è implicito.
Utilizza le parentesi intorno all'espressione a sinistra dell'operatore => per indicare più parametri.
Allo stesso modo, un insieme vuoto di parentesi indica che la funzione non accetta parametri.
A differenza di un'espressione lambda, una dichiarazione lambda può contenere più istruzioni
separate da punto e virgola.
Ricorda che l'istruzione lambda non può essere utilizzata per creare alberi di espressione.
Lambdas può essere emesso sia come `Func` che come` Expression`
Il seguente lambda:
https://riptutorial.com/it/home 285
Può essere passato come argomento per entrambi i metodi:
Le espressioni Lambda possono essere utilizzate per gestire eventi, il che è utile quando:
• Il gestore è corto.
• Il gestore non deve mai essere annullato.
Di seguito viene fornita una buona situazione in cui è possibile utilizzare un gestore di eventi
lambda:
smtpClient.SendCompleted += handler;
smtpClient.SendCompleted -= handler;
La ragione per cui questo è fatto piuttosto che semplicemente ridigitare l'espressione lambda
letteralmente per cancellarla ( -= ) è che il compilatore C # non considererà necessariamente le
due espressioni uguali:
Si noti che se vengono aggiunte istruzioni addizionali all'espressione lambda, le parentesi graffe
circostanti richieste possono essere omesse accidentalmente, senza causare errori in fase di
compilazione. Per esempio:
Questo verrà compilato, ma comporterà l'aggiunta dell'espressione lambda (sender, args) =>
Console.WriteLine("Email sent"); come gestore di eventi ed esecuzione della dichiarazione
https://riptutorial.com/it/home 286
emailSendButton.Enabled = true; subito. Per risolvere questo problema, il contenuto del lambda
deve essere racchiuso tra parentesi graffe. Questo può essere evitato usando le parentesi graffe
dall'inizio, facendo attenzione quando si aggiungono ulteriori istruzioni a un gestore di eventi
lambda o circondando il lambda in parentesi tonde dall'inizio:
https://riptutorial.com/it/home 287
Capitolo 50: eventi
introduzione
Un evento è una notifica che qualcosa si è verificato (come un clic del mouse) o, in alcuni casi, sta
per verificarsi (come una variazione di prezzo).
Le classi possono definire eventi e le loro istanze (oggetti) possono generare questi eventi. Ad
esempio, un pulsante può contenere un evento Click che viene generato quando un utente ha
fatto clic su di esso.
I gestori di eventi sono quindi i metodi che vengono richiamati quando viene generato l'evento
corrispondente. Un modulo può contenere un gestore di eventi Clicked per ogni pulsante che
contiene, per esempio.
Parametri
Parametro Dettagli
Osservazioni
Quando si alza un evento:
• Controllare sempre se il delegato è null . Un delegato nullo significa che l'evento non ha
sottoscrittori. Aumentare un evento senza abbonati comporterà una NullReferenceException .
6.0
• Copia il delegato (ad es. EventName ) in una variabile locale (ad es. eventName ) prima di
verificare la presenza di null / raise dell'evento. Questo evita condizioni di gara in ambienti
multi-thread:
Sbagliato :
https://riptutorial.com/it/home 288
Changed(this, args); // `Changed` is now null, `NullReferenceException` is thrown.
A destra :
6.0
• Utilizzare l'operatore null-condizionale (?.) Per aumentare il metodo anziché il controllo null
del delegato per i sottoscrittori in un'istruzione if : EventName?.Invoke(SenderObject, new
EventArgsT());
• Quando si utilizza l'azione <> per dichiarare i tipi di delegato, la firma del gestore di un
metodo / evento anonimo deve essere uguale al tipo di delegato anonimo dichiarato nella
dichiarazione di evento.
Examples
Dichiarare e sollevare eventi
Dichiarazione di un evento
Puoi dichiarare un evento su qualsiasi class o struct usando la seguente sintassi:
Esiste una sintassi espansa per la dichiarazione degli eventi, in cui si detiene un'istanza privata
dell'evento e si definisce un'istanza pubblica utilizzando add e set accessors. La sintassi è molto
simile alle proprietà C #. In tutti i casi, la sintassi sopra illustrata dovrebbe essere preferita, poiché
il compilatore emette il codice per garantire che più thread possano aggiungere e rimuovere in
modo sicuro i gestori di eventi all'evento della classe.
Alzare l'evento
6.0
https://riptutorial.com/it/home 289
private void OnMyEvent()
{
EventName?.Invoke(this, EventArgs.Empty);
}
6.0
Tieni presente che gli eventi possono essere generati solo dal tipo di dichiarazione. I clienti
possono solo iscriversi / annullare l'iscrizione.
Per le versioni C # precedenti alla 6.0, dove EventName?.Invoke non è supportato, è buona pratica
assegnare l'evento a una variabile temporanea prima del richiamo, come mostrato nell'esempio,
che garantisce la sicurezza del thread nei casi in cui più thread eseguono lo stesso codice. In
caso NullReferenceException possibile che venga generata una NullReferenceException in alcuni
casi in cui più thread utilizzano la stessa istanza di oggetto. In C # 6.0, il compilatore emette un
codice simile a quello mostrato nell'esempio di codice per C # 6.
Dichiarazione di evento:
Iscrizione all'evento:
dinamicamente:
EventName += HandlerName;
Attraverso il Designer:
1. Fare clic sul pulsante Eventi nella finestra delle proprietà del controllo (Lightning bolt)
2. Fai doppio clic sul nome dell'evento:
https://riptutorial.com/it/home 290
3. Visual Studio genererà il codice evento:
Invocare il metodo:
EventName(SenderObject, EventArguments);
Dichiarazione di evento:
Dichiarazione del gestore eventi che utilizza l' operatore lambda => e si iscrive all'evento:
Dichiarazione del gestore eventi che utilizza la sintassi del metodo anonimo delegato :
https://riptutorial.com/it/home 291
pertanto può utilizzare la sintassi precedente senza dover specificare i parametri:
Invocazione dell'evento:
EventName?.Invoke(SenderObject, EventArguments);
Gli eventi possono essere di qualsiasi tipo di delegato, non solo EventHandler e EventHandler<T> .
Per esempio:
//Declaring an event
public event Action<Param1Type, Param2Type, ...> EventName;
È possibile dichiarare più eventi dello stesso tipo in una singola istruzione, in modo simile ai campi
e alle variabili locali (sebbene ciò possa spesso essere una cattiva idea):
Questo dichiara tre eventi separati ( Event1 , Event2 ed Event3 ) tutti di tipo EventHandler .
Nota: sebbene alcuni compilatori possano accettare questa sintassi sia nelle interfacce che nelle
classi, la specifica C # (v5.0 §13.2.3) fornisce la grammatica per le interfacce che non lo
consentono, quindi l'utilizzo di questo nelle interfacce potrebbe non essere affidabile con diversi
compilatori.
https://riptutorial.com/it/home 292
Quando si creano nuovi eventi, per creare un evento personalizzato arg:
• Creare una classe derivante da EventArgs e definire le proprietà per i dati necessari.
• Come convenzione, il nome della classe dovrebbe terminare con EventArgs .
Esempio
PriceChangingEventArgs
Prodotto
int price;
public int Price
{
get { return price; }
set
{
var e = new PriceChangingEventArgs(price, value);
OnPriceChanging(e);
price = value;
}
}
https://riptutorial.com/it/home 293
Modifica la definizione di NewPrice per essere impostabile:
Modifica la definizione di Price per utilizzare e.NewPrice come valore della proprietà, dopo aver
chiamato OnPriceChanging :
int price;
public int Price
{
get { return price; }
set
{
var e = new PriceChangingEventArgs(price, value);
OnPriceChanging(e);
price = e.NewPrice;
}
}
Un evento cancellabile può essere generato da una classe quando sta per eseguire un'azione che
può essere annullata, come ad esempio l'evento FormClosing di un Form .
Esempio
PriceChangingEventArgs
https://riptutorial.com/it/home 294
}
Prodotto
Proprietà dell'evento
Se una classe aumenta di molto il numero di eventi, il costo di archiviazione di un campo per
delegato potrebbe non essere accettabile. .NET Framework fornisce le proprietà degli eventi per
questi casi. In questo modo è possibile utilizzare un'altra struttura dati come EventHandlerList per
memorizzare i delegati dell'evento:
https://riptutorial.com/it/home 295
// Raise the event with the delegate specified by someEventKey
protected void OnSomeEvent(EventArgs e)
{
var handler = (EventHandler)eventDelegates[someEventKey];
if (handler != null)
handler(this, e);
}
}
Questo approccio è ampiamente utilizzato in framework GUI come WinForms in cui i controlli
possono avere dozzine e persino centinaia di eventi.
Notare che EventHandlerList non è thread-safe, quindi se si prevede che la classe venga utilizzata
da più thread, sarà necessario aggiungere istruzioni di blocco o altri meccanismi di
sincronizzazione (o utilizzare una memoria che fornisce sicurezza di thread).
https://riptutorial.com/it/home 296
Capitolo 51: File e streaming I / O
introduzione
Gestisce i file.
Sintassi
• new System.IO.StreamWriter(string path)
• new System.IO.StreamWriter(string path, bool append)
• System.IO.StreamWriter.WriteLine(string text)
• System.IO.StreamWriter.WriteAsync(string text)
• System.IO.Stream.Close()
• System.IO.File.ReadAllText(string path)
• System.IO.File.ReadAllLines(string path)
• System.IO.File.ReadLines(string path)
• System.IO.File.WriteAllText(string path, string text)
• System.IO.File.WriteAllLines(string path, IEnumerable<string> contents)
• System.IO.File.Copy(string source, string dest)
• System.IO.File.Create(string path)
• System.IO.File.Delete(string path)
• System.IO.File.Move(string source, string dest)
• System.IO.Directory.GetFiles(string path)
Parametri
Parametro Dettagli
Se il file esiste, true aggiungerà i dati alla fine del file (append), false
aggiungere
sovrascriverà il file.
Osservazioni
• Assicurati sempre di chiudere gli oggetti Stream . Questo può essere fatto con un blocco
using come mostrato sopra o chiamando manualmente myStream.Close() .
• Assicurarsi che l'utente corrente disponga delle autorizzazioni necessarie sul percorso in cui
https://riptutorial.com/it/home 297
si sta tentando di creare il file.
• Le stringhe di Verbatim devono essere utilizzate quando si dichiara una stringa di percorso
che include barre retroverse, ad esempio: @"C:\MyFolder\MyFile.txt"
Examples
Lettura da un file usando la classe System.IO.File
Puoi anche leggere un file come una matrice di linee usando la funzione
System.IO.File.ReadAllLines :
La classe System.IO.StreamWriter :
Utilizzando il metodo WriteLine , è possibile scrivere il contenuto riga per riga in un file.
Si noti l'uso della parola chiave using che si assicura che l'oggetto StreamWriter sia eliminato non
appena esce dall'ambito e quindi il file viene chiuso.
string[] lines = { "My first string", "My second string", "and even a third string" };
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\MyFolder\OutputText.txt"))
{
foreach (string line in lines)
{
sw.WriteLine(line);
}
}
Si noti che StreamWriter può ricevere un secondo parametro bool nel suo costruttore,
consentendo di Append a un file invece di sovrascrivere il file:
https://riptutorial.com/it/home 298
Scrivere su un file usando la classe System.IO.File
string[] lines = { "My first string", "My second string", "and even a third string" };
System.IO.File.WriteAllLines(@"C:\MyFolder\OutputFile.txt", lines);
È importante notare che chiamare ToArray , ToList o un'altra funzione simile costringerà tutte le
linee a essere caricate contemporaneamente, il che significa che il vantaggio dell'utilizzo di
ReadLines è annullato. È meglio enumerare su IEnumerable utilizzando un ciclo foreach o LINQ se si
utilizza questo metodo.
Crea file
Usando il metodo Create della classe statica File possiamo creare file. Il metodo crea il file nel
percorso specificato, allo stesso tempo apre il file e ci dà il FileStream del file. Assicurati di
chiudere il file dopo aver finito con esso.
EX1:
EX2:
https://riptutorial.com/it/home 299
{
/// you can write to the fileStream1
}
EX3:
File.Create("samplePath").Close();
Classe FileStream
Ci sono molti sovraccarichi di questo costruttore di classi che è in realtà ben documentato qui . Di
seguito l'esempio è per quello che copre le funzionalità più utilizzate di questa classe.
FileMode: risposte "Se il file deve essere creato? Aperto? Creare se non esiste, quindi aprire?" un
po 'domande.
FileAccess: Answers "Devo essere in grado di leggere il file, scrivere sul file o entrambi?" un po
'domande.
FileShare: Answers "Gli altri utenti possono leggere, scrivere, ecc. Sul file mentre lo sto usando
simultaneamente?" un po 'domande.
Copia il file
File classe statica dei File può essere facilmente utilizzata per questo scopo.
File.Copy(@"sourcePath\abc.txt", @"destinationPath\abc.txt");
File.Copy(@"sourcePath\abc.txt", @"destinationPath\xyz.txt");
Osservazione: con questo metodo, il file viene copiato, il che significa che verrà letto dall'origine
e quindi scritto nel percorso di destinazione. Questo è un processo che consuma risorse, richiede
tempo relativamente alla dimensione del file e può bloccare il programma se non si utilizzano i
thread.
Sposta il file
La classe statica del file può essere facilmente utilizzata per questo scopo.
File.Move(@"sourcePath\abc.txt", @"destinationPath\xyz.txt");
https://riptutorial.com/it/home 300
Nota 1: modifica solo l'indice del file (se il file viene spostato nello stesso volume). Questa
operazione non richiede tempo relativamente alla dimensione del file.
Cancella il file
Mentre Delete non genera un'eccezione se il file non esiste, genererà un'eccezione, ad esempio
se il percorso specificato non è valido o se il chiamante non dispone delle autorizzazioni richieste.
Dovresti sempre inserire le chiamate su Delete nel blocco try-catch e gestire tutte le eccezioni
previste. In caso di condizioni di gara possibili, avvolgere la logica all'interno dell'istruzione di
blocco .
File e directory
Restituisce un array di FileInfo , che rappresenta tutti i file nella directory specificata.
Restituisce un array di FileInfo , che rappresenta tutti i file nella directory specificata con
l'estensione specificata.
https://riptutorial.com/it/home 301
Capitolo 52: FileSystemWatcher
Sintassi
• public FileSystemWatcher ()
• public FileSystemWatcher (percorso stringa)
• public FileSystemWatcher (percorso stringa, filtro stringa)
Parametri
sentiero filtro
Examples
FileWatcher di base
Utilizzare gli spazi dei nomi System.Diagnostics e System.IO per questo esempio.
FileSystemWatcher watcher;
https://riptutorial.com/it/home 302
}
IsFileReady
Un errore comune che molte persone iniziano con FileSystemWatcher non sta prendendo in
considerazione che l'evento FileWatcher viene generato non appena viene creato il file. Tuttavia,
potrebbe essere necessario del tempo per il completamento del file.
Esempio :
Ad esempio, prendi una dimensione del file di 1 GB. Il file apr ask creato da un altro programma
(Explorer.exe lo copia da qualche parte) ma ci vorranno alcuni minuti per terminare quel processo.
L'evento aumenta il tempo di creazione e devi aspettare che il file sia pronto per essere copiato.
}
}
catch (Exception)
{
return false;
}
}
https://riptutorial.com/it/home 303
Capitolo 53: Filtri di azione
Examples
Filtri di azione personalizzati
Scriviamo filtri di azione personalizzati per vari motivi. Potremmo avere un filtro azioni
personalizzato per la registrazione o per salvare i dati nel database prima di qualsiasi esecuzione
di azioni. Potremmo anche averne uno per prelevare i dati dal database e impostarlo come valori
globali dell'applicazione.
OnActionExecuting : questo metodo viene chiamato prima che venga eseguita un'azione del
controllore.
OnActionExecuted : questo metodo viene chiamato dopo l'esecuzione di un'azione del controller.
using System;
using System.Diagnostics;
using System.Web.Mvc;
namespace WebApplication1
{
https://riptutorial.com/it/home 304
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controllerName = filterContext.RouteData.Values["controller"];
var actionName = filterContext.RouteData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}",
"onactionexecuting", controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
base.OnActionExecuting(filterContext);
}
}
}
https://riptutorial.com/it/home 305
Capitolo 54: Func delegati
Sintassi
• public delegate TResult Func<in T, out TResult>(T arg)
• public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2)
• public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3)
• public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3
arg3, T4 arg4)
Parametri
Parametro Dettagli
Examples
Senza parametri
Questo esempio mostra come creare un delegato che incapsula il metodo che restituisce l'ora
corrente
https://riptutorial.com/it/home 306
static void Main(string[] args)
{
Func<DateTime> method = UTCNow;
// method points to the UTCNow method
// that retuns current UTC time
DateTime utcNow = method();
method = LocalNow;
// now method points to the LocalNow method
// that returns local time
method = Multiplication;
// now method points to the Multiplication method
In entrambi i casi, ora possiamo invocare il metodo memorizzato all'interno di un square come
questo:
var sq = square.Invoke(2);
https://riptutorial.com/it/home 307
O come una stenografia:
var sq = square(2);
Si noti che per l'assegnazione del tipo sicuro, i tipi di parametri e il tipo restituito del metodo
anonimo devono corrispondere a quelli del tipo delegato:
class Program
{
static Employee FindByTitle(String title)
{
// This is a stub for a method that returns
// an employee that has the specified title.
return new Employee();
}
}
}
https://riptutorial.com/it/home 308
Capitolo 55: Funzione con più valori di
ritorno
Osservazioni
Non c'è una risposta inerente in C # a questo - così chiamato - bisogno. Tuttavia ci sono soluzioni
alternative per soddisfare questa esigenza.
Il motivo per cui qualificano il bisogno come "così chiamato" è che abbiamo bisogno solo di metodi
con 2 o più di 2 valori da restituire quando violiamo i principi di programmazione. Soprattutto il
principio della singola responsabilità .
Quindi, sarebbe meglio essere avvisati quando abbiamo bisogno di funzioni che restituiscono 2 o
più valori e migliorare il nostro design.
Examples
soluzione "oggetto anonimo" + "parola chiave dinamica"
Console.WriteLine(x.a);
Console.WriteLine(x.b);
Soluzione tuple
Puoi restituire un'istanza della classe Tuple dalla tua funzione con due parametri del modello come
Tuple<string, MyClass> :
https://riptutorial.com/it/home 309
Console.WriteLine(x.Item1);
Console.WriteLine(x.Item2);
La parola chiave ref viene utilizzata per passare un argomento come riferimento . out farà lo
stesso di ref ma non richiede un valore assegnato dal chiamante prima di chiamare la funzione.
Parametro Ref : -Se si desidera passare una variabile come parametro ref, è necessario
inizializzarla prima di passarla come parametro ref al metodo.
Out Parameter: - Se si desidera passare una variabile come parametro out, non è necessario
inizializzarla prima di passarla come parametro out al metodo.
private static void AddOrMult(int a, int b, ref int add, ref int mult) //AddOrMult(int a, int
b, out int add, out int mult)
{
add = a + b;
mult = a * b;
}
https://riptutorial.com/it/home 310
Capitolo 56: Funzioni hash
Osservazioni
MD5 e SHA1 non sono sicuri e dovrebbero essere evitati. Gli esempi esistono per scopi didattici e
perché il software legacy può ancora utilizzare questi algoritmi.
Examples
MD5
Le funzioni hash associano le stringhe binarie di una lunghezza arbitraria a stringhe binarie di una
lunghezza fissa.
L'algoritmo MD5 è una funzione hash ampiamente utilizzata che produce un valore hash a 128 bit
(16 byte, 32 caratteri esadecimali).
Esempio:
using System;
using System.Security.Cryptography;
using System.Text;
https://riptutorial.com/it/home 311
Output: l'hash MD5 di Hello World! è: ED076287532E86365E841E92BFC50D8C
Problemi di sicurezza:
Come la maggior parte delle funzioni di hash, MD5 non è né crittografia né codifica. Può essere
invertito con un attacco a forza bruta e soffre di ampie vulnerabilità contro gli attacchi di collisione
e di preimage.
SHA1
using System;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string source = "Hello World!";
using (SHA1 sha1Hash = SHA1.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(source);
byte[] hashBytes = sha1Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-",String.Empty);
Produzione:
SHA256
using System;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string source = "Hello World!";
using (SHA256 sha256Hash = SHA256.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(source);
https://riptutorial.com/it/home 312
byte[] hashBytes = sha256Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-", String.Empty);
Produzione:
SHA384
using System;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string source = "Hello World!";
using (SHA384 sha384Hash = SHA384.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(source);
byte[] hashBytes = sha384Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-", String.Empty);
Produzione:
SHA512
using System;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
https://riptutorial.com/it/home 313
static void Main(string[] args)
{
string source = "Hello World!";
using (SHA512 sha512Hash = SHA512.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(source);
byte[] hashBytes = sha512Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-", String.Empty);
PBKDF2 ("Funzione di derivazione chiave basata su password 2") è una delle funzioni hash
consigliate per l'hashing delle password. Fa parte di rfc-2898 .
using System.Security.Cryptography;
...
iterazioni:
Un numero elevato di iterazioni rallenterà l'algoritmo, il che rende molto più difficile il crack delle
password. Si raccomanda quindi un numero elevato di iterazioni. Ad esempio, PBKDF2 è un
ordine di grandezza più lento di MD5.
Sale:
https://riptutorial.com/it/home 314
Un salt impedirà la ricerca di valori hash nelle tabelle arcobaleno. Deve essere memorizzato
insieme all'hash della password. Si consiglia un sale per password (non un sale globale).
using System;
using System.Linq;
using System.Security.Cryptography;
namespace YourCryptoNamespace
{
/// <summary>
/// Salted password hashing with PBKDF2-SHA1.
/// Compatibility: .NET 3.0 and later.
/// </summary>
/// <remarks>See http://crackstation.net/hashing-security.htm for much more on password
hashing.</remarks>
public static class PasswordHashProvider
{
/// <summary>
/// The salt byte size, 64 length ensures safety but could be increased / decreased
/// </summary>
private const int SaltByteSize = 64;
/// <summary>
/// The hash byte size,
/// </summary>
private const int HashByteSize = 64;
/// <summary>
/// High iteration count is less likely to be cracked
/// </summary>
private const int Pbkdf2Iterations = 10000;
/// <summary>
/// Creates a salted PBKDF2 hash of the password.
/// </summary>
/// <remarks>
/// The salt and the hash have to be persisted side by side for the password. They could
be persisted as bytes or as a string using the convenience methods in the next class to
convert from byte[] to string and later back again when executing password validation.
/// </remarks>
/// <param name="password">The password to hash.</param>
/// <returns>The hash of the password.</returns>
public static PasswordHashContainer CreateHash(string password)
{
// Generate a random salt
using (var csprng = new RNGCryptoServiceProvider())
{
// create a unique salt for every password hash to prevent rainbow and dictionary
based attacks
var salt = new byte[SaltByteSize];
csprng.GetBytes(salt);
https://riptutorial.com/it/home 315
/// Recreates a password hash based on the incoming password string and the stored salt
/// </summary>
/// <param name="password">The password to check.</param>
/// <param name="salt">The salt existing.</param>
/// <returns>the generated hash based on the password and salt</returns>
public static byte[] CreateHash(string password, byte[] salt)
{
// Extract the parameters from the hash
return Pbkdf2(password, salt, Pbkdf2Iterations, HashByteSize);
}
/// <summary>
/// Validates a password given a hash of the correct one.
/// </summary>
/// <param name="password">The password to check.</param>
/// <param name="salt">The existing stored salt.</param>
/// <param name="correctHash">The hash of the existing password.</param>
/// <returns><c>true</c> if the password is correct. <c>false</c> otherwise. </returns>
public static bool ValidatePassword(string password, byte[] salt, byte[] correctHash)
{
// Extract the parameters from the hash
byte[] testHash = Pbkdf2(password, salt, Pbkdf2Iterations, HashByteSize);
return CompareHashes(correctHash, testHash);
}
/// <summary>
/// Compares two byte arrays (hashes)
/// </summary>
/// <param name="array1">The array1.</param>
/// <param name="array2">The array2.</param>
/// <returns><c>true</c> if they are the same, otherwise <c>false</c></returns>
public static bool CompareHashes(byte[] array1, byte[] array2)
{
if (array1.Length != array2.Length) return false;
return !array1.Where((t, i) => t != array2[i]).Any();
}
/// <summary>
/// Computes the PBKDF2-SHA1 hash of a password.
/// </summary>
/// <param name="password">The password to hash.</param>
/// <param name="salt">The salt.</param>
/// <param name="iterations">The PBKDF2 iteration count.</param>
/// <param name="outputBytes">The length of the hash to generate, in bytes.</param>
/// <returns>A hash of the password.</returns>
private static byte[] Pbkdf2(string password, byte[] salt, int iterations, int
outputBytes)
{
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt))
{
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
}
}
/// <summary>
/// Container for password hash and salt and iterations.
/// </summary>
public sealed class PasswordHashContainer
{
/// <summary>
https://riptutorial.com/it/home 316
/// Gets the hashed password.
/// </summary>
public byte[] HashedPassword { get; private set; }
/// <summary>
/// Gets the salt.
/// </summary>
public byte[] Salt { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="PasswordHashContainer" /> class.
/// </summary>
/// <param name="hashedPassword">The hashed password.</param>
/// <param name="salt">The salt.</param>
public PasswordHashContainer(byte[] hashedPassword, byte[] salt)
{
this.HashedPassword = hashedPassword;
this.Salt = salt;
}
}
/// <summary>
/// Convenience methods for converting between hex strings and byte array.
/// </summary>
public static class ByteConverter
{
/// <summary>
/// Converts the hex representation string to an array of bytes
/// </summary>
/// <param name="hexedString">The hexed string.</param>
/// <returns></returns>
public static byte[] GetHexBytes(string hexedString)
{
var bytes = new byte[hexedString.Length / 2];
for (var i = 0; i < bytes.Length; i++)
{
var strPos = i * 2;
var chars = hexedString.Substring(strPos, 2);
bytes[i] = Convert.ToByte(chars, 16);
}
return bytes;
}
/// <summary>
/// Gets a hex string representation of the byte array passed in.
/// </summary>
/// <param name="bytes">The bytes.</param>
public static string GetHexString(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", "").ToUpper();
}
}
}
/*
* Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
* Copyright (c) 2013, Taylor Hornby
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
https://riptutorial.com/it/home 317
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
Si prega di consultare questa eccellente risorsa Crackstation - Salted Password Hashing - Farlo
bene per ulteriori informazioni. Parte di questa soluzione (la funzione di hashing) era basata sul
codice di quel sito.
https://riptutorial.com/it/home 318
Capitolo 57: Garbage Collector in .Net
Examples
Compattazione del mucchio di oggetti di grandi dimensioni
Di default il Large Object Heap non è compattato a differenza del classico Object Heap che può
portare alla frammentazione della memoria e, inoltre, può portare a OutOfMemoryException s
A partire da .NET 4.5.1 esiste un'opzione per comprimere esplicitamente l'heap di oggetti di grandi
dimensioni (insieme a una garbage collection):
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
Proprio come qualsiasi richiesta di garbage collection esplicita (si chiama richiesta perché CLR
non è obbligato a condurla) usa con cautela e, per impostazione predefinita, evitala se puoi
perché può GC statistiche di GC , diminuendo le sue prestazioni.
Riferimenti deboli
In .NET, il GC alloca gli oggetti quando non ci sono riferimenti a loro lasciati. Pertanto, mentre un
oggetto può ancora essere raggiunto dal codice (c'è un forte riferimento ad esso), il GC non
assegnerà questo oggetto. Questo può diventare un problema se ci sono molti oggetti di grandi
dimensioni.
Uso semplice:
GC.Collect();
Quindi riferimenti deboli potrebbero essere usati per mantenere, per esempio, una cache di
oggetti. Tuttavia, è importante ricordare che c'è sempre il rischio che il garbage collector
raggiunga l'oggetto prima che venga ristabilito un riferimento forte.
https://riptutorial.com/it/home 319
I riferimenti deboli sono anche utili per evitare perdite di memoria. Un tipico caso d'uso è con gli
eventi.
Questo codice registra un gestore di eventi e crea un riferimento forte dall'origine evento
all'oggetto in ascolto. Se l'oggetto di origine ha una durata maggiore rispetto al listener e il listener
non ha più bisogno dell'evento quando non ci sono altri riferimenti ad esso, l'uso di eventi .NET
normali causa una perdita di memoria: l'oggetto di origine contiene oggetti listener in memoria che
dovrebbe essere raccolta dei rifiuti
In questo caso, potrebbe essere una buona idea usare il modello di evento debole .
Qualcosa di simile a:
add(handler);
}
}
https://riptutorial.com/it/home 320
In questo caso ovviamente abbiamo alcune restrizioni: l'evento deve essere a
• Usa riferimenti deboli lunghi solo quando è necessario poiché lo stato dell'oggetto è
imprevedibile dopo la finalizzazione.
• Evita di usare riferimenti deboli a oggetti piccoli perché il puntatore stesso potrebbe essere
grande o più grande.
• Evitare l'uso di riferimenti deboli come soluzione automatica ai problemi di gestione della
memoria. Invece, sviluppare una politica di caching efficace per la gestione degli oggetti
dell'applicazione.
https://riptutorial.com/it/home 321
Capitolo 58: Generare numeri casuali in C #
Sintassi
• Casuale()
• int Successivo ()
Parametri
parametri Dettagli
I numeri generati non saranno più piccoli di questo valore. Se non impostato,
minValue
il valore predefinito è 0.
valore di
Restituisce un numero con valore casuale.
ritorno
Osservazioni
Il seme casuale generato dal sistema non è lo stesso in ogni altra corsa.
Examples
Genera un int casuale
https://riptutorial.com/it/home 322
Genera un doppio casuale
Quando si creano istanze Random con lo stesso seme, verranno generati gli stessi numeri.
int seed = 5;
for (int i = 0; i < 2; i++)
{
Console.WriteLine("Random instance " + i);
Random rnd = new Random(seed);
for (int j = 0; j < 5; j++)
{
Console.Write(rnd.Next());
Console.Write(" ");
}
Console.WriteLine();
}
Produzione:
Random instance 0
726643700 610783965 564707973 1342984399 995276750
Random instance 1
726643700 610783965 564707973 1342984399 995276750
https://riptutorial.com/it/home 323
Console.WriteLine("First 5 random number in rnd2");
for (int i = 0; i < 5; i++)
Console.WriteLine(rnd2.Next());
Un altro modo per ottenere semi diversi è usare un'altra istanza Random per recuperare i valori
seme.
Ciò consente inoltre di controllare il risultato di tutte le istanze Random impostando solo il valore di
rndSeeds per rndSeeds . Tutte le altre istanze saranno derivate deterministicamente dal valore di
seme singolo.
Generare una lettera casuale tra a e z usando il sovraccarico Next() per un dato intervallo di
numeri, quindi convertire l' int risultante in un char
Un bisogno comune di numeri casuali per generare un numero che è X% di qualche valore
massimo. questo può essere fatto trattando il risultato di NextDouble() come percentuale:
https://riptutorial.com/it/home 324
Capitolo 59: Generatore di query Lambda
generico
Osservazioni
La classe si chiama ExpressionBuilder . Ha tre proprietà:
Un metodo pubblico GetExpression che restituisce l'espressione lambda e tre metodi privati:
• Expression GetExpression<T>
• BinaryExpression GetExpression<T>
• ConstantExpression GetConstant
Examples
Classe QueryFilter
https://riptutorial.com/it/home 325
{
Contains,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqualTo,
StartsWith,
EndsWith,
Equals,
NotEqual
}
Metodo GetExpression
// Remove the two just used filters, for the method in the next iteration
finds the next filters
filters.Remove(f1);
filters.Remove(f2);
https://riptutorial.com/it/home 326
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
}
else
// It is result from direct call.
exp = GetExpression<T>(param, filters[0]);
Per un filtro:
Qui è dove viene creata la query, riceve un parametro di espressione e un filtro.
//Represents an expression that has a constant value, so here we are accessing for
example:
// the values of the Property "Name".
// Also for clarity sake the GetConstant will be explained in another example.
ConstantExpression constant = GetConstant(member.Type, queryFilter.Value);
case Operator.Contains:
return Expression.Call(member, ContainsMethod, constant);
case Operator.GreaterThan:
return Expression.GreaterThan(member, constant);
case Operator.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case Operator.LessThan:
return Expression.LessThan(member, constant);
case Operator.LessThanOrEqualTo:
return Expression.LessThanOrEqual(member, constant);
case Operator.StartsWith:
https://riptutorial.com/it/home 327
return Expression.Call(member, StartsWithMethod, constant);
case Operator.EndsWith:
return Expression.Call(member, EndsWithMethod, constant);
}
return null;
}
Metodo ConstantExpression
https://riptutorial.com/it/home 328
}
else if (type == typeof(decimal))
{
decimal number;
decimal.TryParse(value, out number);
constant = Expression.Constant(number);
}
return constant;
}
uso
Filtri di raccolta = nuova lista (); Filtro QueryFilter = new QueryFilter ("Nome", "Burger",
Operator.StartsWith); filters.Add (filtro);
In questo caso, si tratta di una query contro l'entità Cibo, che desidera trovare tutti gli alimenti che
iniziano con "Burger" nel nome.
Produzione:
query = {parm => a.parm.StartsWith("Burger")}
https://riptutorial.com/it/home 329
Capitolo 60: Generazione del codice T4
Sintassi
• Sintassi T4
• <#@...#> // Dichiarazione delle proprietà inclusi modelli, assiemi e spazi dei nomi e la lingua
utilizzata dal modello
• Plain Text // Dichiarazione del testo che può essere ricollegato per i file generati
• <#=...#> // Dichiarare gli script
• <#+...#> // Dichiarare scriptlet
• <#...#> // Dichiarare blocchi di testo
Examples
Generazione del codice runtime
https://riptutorial.com/it/home 330
Capitolo 61: Generics
Sintassi
• public void SomeMethod <T> () { }
• public void SomeMethod<T, V>() { }
• public T SomeMethod<T>(IEnumerable<T> sequence) { ... }
• public void SomeMethod<T>() where T : new() { }
• public void SomeMethod<T, V>() where T : new() where V : struct { }
• public void SomeMethod<T>() where T: IDisposable { }
• public void SomeMethod<T>() where T: Foo { }
• public class MyClass<T> { public T Data {get; set; } }
Parametri
Osservazioni
Generics in C # sono supportati fino al runtime: i tipi generici creati con C # conservano la loro
semantica generica anche dopo essere stati compilati in CIL .
Ciò significa in effetti che, in C #, è possibile riflettere su tipi generici e vederli come sono stati
dichiarati o controllare se un oggetto è un'istanza di un tipo generico, ad esempio. Ciò è in
contrasto con la cancellazione del tipo , in cui le informazioni di tipo generico vengono rimosse
durante la compilazione. È anche in contrasto con l'approccio del modello ai generici, in cui più tipi
generici concreti diventano più tipi non generici in fase di runtime e tutti i metadati necessari per
un'ulteriore definizione delle definizioni del tipo generico originale vengono persi.
Prestare attenzione, tuttavia, quando si riflette su tipi generici: i nomi dei tipi generici verranno
alterati nella compilazione, sostituendo le parentesi angolate ei nomi dei parametri di tipo con un
apice seguito dal numero di parametri di tipo generico. Pertanto, un Dictionary<TKey, Tvalue> sarà
tradotto nel Dictionary`2 .
Examples
Tipo Parametri (Classi)
Dichiarazione:
https://riptutorial.com/it/home 331
}
Inizializzazione:
Dichiarazione:
Invocazione:
Non è necessario fornire argomentazioni di tipo a un metodo genrico, poiché il compilatore può
implicitamente inferire il tipo.
int x =10;
int y =20;
string z = "test";
MyGenericMethod(x,y,z);
Tuttavia, se c'è un'ambiguità, i metodi generici devono essere chiamati con tipo arguemnts come
Dichiarazione:
https://riptutorial.com/it/home 332
Utilizzo (come il tipo di un parametro):
Quando si passano argomenti formali a un metodo generico, argomenti di tipo generico rilevanti
possono essere normalmente dedotti implicitamente. Se è possibile dedurre tutti i tipi generici,
specificarli nella sintassi è facoltativo.
M<object>(new object());
M(new object());
M<string>("");
M("");
M<object>("");
M((object) "");
M("" as object);
Si noti che se non è possibile dedurre almeno un argomento di tipo, è necessario specificarli tutti.
Si consideri il seguente metodo generico. Il primo argomento di tipo generico è lo stesso del tipo
dell'argomento formale. Ma non esiste una tale relazione per il secondo argomento di tipo
generico. Pertanto, il compilatore non ha modo di inferire il secondo argomento di tipo generico in
qualsiasi chiamata a questo metodo.
https://riptutorial.com/it/home 333
X("");
Anche questo non funziona, perché il compilatore non è sicuro se stiamo specificando il primo o il
secondo parametro generico (entrambi sarebbero validi come object ):
X<object>("");
X<string, object>("");
I vincoli di tipo sono in grado di forzare un parametro di tipo per implementare una determinata
interfaccia o classe.
interface IType;
interface IAnotherType;
class NonGeneric
{
// T must be a subtype of IType
public void DoSomething<T>(T arg)
where T : IType
{
}
}
https://riptutorial.com/it/home 334
class Generic<T, T1>
where T : IType
where T1 : Base, new()
{
}
I vincoli di tipo funzionano allo stesso modo dell'ereditarietà, in quanto è possibile specificare più
interfacce come vincoli sul tipo generico, ma solo una classe:
class A { /* ... */ }
class B { /* ... */ }
interface I1 { }
interface I2 { }
class Generic<T>
where T : A, I1, I2
{
}
class Generic2<T>
where T : A, B //Compilation error
{
}
Un'altra regola è che la classe deve essere aggiunta come primo vincolo e quindi le interfacce:
class Generic<T>
where T : A, I1
{
}
class Generic2<T>
where T : I1, A //Compilation error
{
}
Tutti i vincoli dichiarati devono essere soddisfatti simultaneamente affinché una determinata
istanza generica funzioni. Non c'è modo di specificare due o più insiemi alternativi di vincoli.
È possibile specificare se l'argomento type debba essere un tipo di riferimento o un tipo di valore
utilizzando la rispettiva class vincoli o struct . Se questi vincoli vengono utilizzati, devono essere
definiti prima di poter elencare tutti gli altri vincoli (ad esempio un genitore o un new() ).
// TRef must be a reference type, the use of Int32, Single, etc. is invalid.
// Interfaces are valid, as they are reference types
class AcceptsRefType<TRef>
where TRef : class
{
// TStruct must be a value type.
public void AcceptStruct<TStruct>()
where TStruct : struct
{
https://riptutorial.com/it/home 335
}
Utilizzando il new() vincolo new() , è possibile applicare i parametri del tipo per definire un
costruttore vuoto (predefinito).
class Foo
{
public Foo () { }
}
class Bar
{
public Bar (string s) { ... }
}
class Factory<T>
where T : new()
{
public T Create()
{
return new T();
}
}
'Bar' deve essere un tipo non astratto con un costruttore pubblico senza parametri per
utilizzarlo come parametro 'T' nel tipo generico o nel metodo 'Factory'
Non esiste alcun vincolo per un costruttore con parametri, sono supportati solo costruttori senza
parametri.
Gli sviluppatori possono essere colti dal fatto che l'inferenza di tipo non funziona per i costruttori:
class Tuple<T1,T2>
{
public Tuple(T1 value1, T2 value2)
{
}
https://riptutorial.com/it/home 336
}
Il primo modo di creare un'istanza senza specificare esplicitamente i parametri di tipo causerà
errori di compilazione che direbbero:
L'utilizzo del tipo generico 'Tuple <T1, T2>' richiede due argomenti di tipo
class NameGetter<T>
{
public string GetTypeName()
{
return typeof(T).Name;
}
}
Esistono diversi casi in cui è necessario specificare esplicitamente i parametri del tipo per un
metodo generico. In entrambi i casi seguenti, il compilatore non è in grado di dedurre tutti i
parametri del tipo dai parametri del metodo specificato.
Il secondo caso è quando uno (o più) dei parametri del tipo non fa parte dei parametri del metodo:
https://riptutorial.com/it/home 337
public K SomeMethod<K, V>(V input)
{
return default(K);
}
Questo è un esempio di come usare il tipo generico TFood all'interno del metodo Eat sulla classe
Animal
https://riptutorial.com/it/home 338
Puoi chiamare il metodo Eat in questo modo:
sheep.Eat(grass);
//Output: Grass was eaten by: Herbivore
lion.Eat(sheep);
//Output: Herbivore was eaten by: Carnivore
sheep.Eat(lion);
Non sarà possibile perché l'oggetto leone non implementa l'interfaccia IFood. Tentare di effettuare
la chiamata sopra genererà un errore del compilatore: "Il tipo 'Carnivore' non può essere utilizzato
come parametro di tipo 'TFood' nel tipo generico o nel metodo 'Animal.Eat (TFood)'. Non c'è
conversione implicita di riferimento da ' Carnivore 'a' IFood '. "
covarianza
Questa relazione vale perché IEnumerable produce T s ma non li consuma. Un oggetto che produce
Dog s può essere usato come se producesse Animal s.
I parametri di tipo Covariant vengono dichiarati utilizzando la parola chiave out , poiché il
parametro deve essere utilizzato solo come output .
Un parametro di tipo dichiarato come covariante potrebbe non apparire come input.
https://riptutorial.com/it/home 339
}
using NUnit.Framework;
namespace ToyStore
{
enum Taste { Bitter, Sweet };
interface IWidget
{
int Weight { get; }
}
public Toy Create() { return new Toy { Weight = StandardWeight, Taste = StandardTaste };
}
}
[TestFixture]
public class GivenAToyFactory
{
[Test]
public static void WhenUsingToyFactoryToMakeWidgets()
{
var toyFactory = new ToyFactory();
controvarianza
https://riptutorial.com/it/home 340
Quando è un IComparer<T> un sottotipo di un altro IComparer<T1> ? Quando T1 è un sottotipo di T
IComparer è controvariante nel suo parametro T , il che significa che la relazione del sottotipo di
IComparer va nella direzione opposta a quella di T
Questa relazione vale perché IComparer consuma T s ma non li produce. Un oggetto che può
confrontare due Animal può essere usato per confrontare due Dog .
Un parametro di tipo dichiarato come controvariante potrebbe non apparire come output.
invarianza
IList<T> non è mai un sottotipo di un diverso IList<T1> . IList è invariante nel suo parametro di
tipo.
Non esiste una relazione di sottotipo per gli elenchi poiché è possibile inserire valori in un elenco e
ricavare valori da un elenco.
Se IList fosse covariante, saresti in grado di aggiungere elementi del sottotipo sbagliato a una
data lista.
https://riptutorial.com/it/home 341
Se IList fosse controverso, saresti in grado di estrarre i valori del sottotipo errato da una lista
data.
IList<Dog> dogs = new List<Animal> { new Dog(), new Giraffe() }; // if this were allowed...
Dog dog = dogs[1]; // ... then this would be allowed, which is bad!
I parametri di tipo invariante sono dichiarati omettendo sia le parole chiave in e out .
Interfacce varianti
class MyClass
{
public T Bad<out T, in T1>(T1 t1) // not allowed
{
// ...
}
}
https://riptutorial.com/it/home 342
IFoo<Animal, Dog, int> foo1 = /* ... */;
IFoo<Dog, Animal, int> foo2 = foo1;
// IFoo<Animal, Dog, int> is a subtype of IFoo<Dog, Animal, int>
Delegati varianti
Ciò deriva dal Principio di sostituzione di Liskov , che stabilisce (tra le altre cose) che un metodo D
può essere considerato più derivato di un metodo B se:
Se un tipo covariante viene visualizzato come output, il tipo contenente è covariante. Produrre un
produttore di T s è come produrre T s.
https://riptutorial.com/it/home 343
Se un tipo controvariante appare come input, il tipo contenente è covariante. Consumare un
consumatore di T s è come produrre T s.
Se la logica di classe generica o metodo richiede il controllo parità di valore aventi tipo generico,
utilizzare EqualityComparer<TType>.Default proprietà :
/// <summary>
/// Converts a data type to another data type.
/// </summary>
public static class Cast
{
/// <summary>
/// Converts input to Type of default value or given as typeparam T
/// </summary>
/// <typeparam name="T">typeparam is the type in which value will be returned, it
could be any type eg. int, string, bool, decimal etc.</typeparam>
/// <param name="input">Input that need to be converted to specified type</param>
/// <param name="defaultValue">defaultValue will be returned in case of value is null
or any exception occures</param>
/// <returns>Input is converted in Type of default value or given as typeparam T and
returned</returns>
public static T To<T>(object input, T defaultValue)
{
var result = defaultValue;
try
{
if (input == null || input == DBNull.Value) return result;
if (typeof (T).IsEnum)
{
result = (T) Enum.ToObject(typeof (T), To(input,
Convert.ToInt32(defaultValue)));
}
https://riptutorial.com/it/home 344
else
{
result = (T) Convert.ChangeType(input, typeof (T));
}
}
catch (Exception ex)
{
Tracer.Current.LogException(ex);
}
return result;
}
/// <summary>
/// Converts input to Type of typeparam T
/// </summary>
/// <typeparam name="T">typeparam is the type in which value will be returned, it
could be any type eg. int, string, bool, decimal etc.</typeparam>
/// <param name="input">Input that need to be converted to specified type</param>
/// <returns>Input is converted in Type of default value or given as typeparam T and
returned</returns>
public static T To<T>(object input)
{
return To(input, default(T));
}
usi:
std.Name = Cast.To<string>(drConnection["Name"]);
std.Age = Cast.To<int>(drConnection["Age"]);
std.IsPassed = Cast.To<bool>(drConnection["IsPassed"]);
/// <summary>
/// Read configuration values from app.config and convert to specified types
/// </summary>
public static class ConfigurationReader
{
/// <summary>
/// Get value from AppSettings by key, convert to Type of default value or typeparam T
and return
/// </summary>
/// <typeparam name="T">typeparam is the type in which value will be returned, it
https://riptutorial.com/it/home 345
could be any type eg. int, string, bool, decimal etc.</typeparam>
/// <param name="strKey">key to find value from AppSettings</param>
/// <param name="defaultValue">defaultValue will be returned in case of value is null
or any exception occures</param>
/// <returns>AppSettings value against key is returned in Type of default value or
given as typeparam T</returns>
public static T GetConfigKeyValue<T>(string strKey, T defaultValue)
{
var result = defaultValue;
try
{
if (ConfigurationManager.AppSettings[strKey] != null)
result = (T)Convert.ChangeType(ConfigurationManager.AppSettings[strKey],
typeof(T));
}
catch (Exception ex)
{
Tracer.Current.LogException(ex);
}
return result;
}
/// <summary>
/// Get value from AppSettings by key, convert to Type of default value or typeparam T
and return
/// </summary>
/// <typeparam name="T">typeparam is the type in which value will be returned, it
could be any type eg. int, string, bool, decimal etc.</typeparam>
/// <param name="strKey">key to find value from AppSettings</param>
/// <returns>AppSettings value against key is returned in Type given as typeparam
T</returns>
public static T GetConfigKeyValue<T>(string strKey)
{
return GetConfigKeyValue(strKey, default(T));
}
usi:
https://riptutorial.com/it/home 346
Capitolo 62: Gestione di FormatException
durante la conversione di stringhe in altri tipi
Examples
Conversione da stringa a intero
Sono disponibili vari metodi per convertire esplicitamente una string in un integer , ad esempio:
1. Convert.ToInt16();
2. Convert.ToInt32();
3. Convert.ToInt64();
4. int.Parse();
Ma tutti questi metodi generano un FormatException , se la stringa di input contiene caratteri non
numerici. Per questo, abbiamo bisogno di scrivere un'ulteriore gestione delle eccezioni (
try..catch ) per trattarli in questi casi.
Esempio 1: Convert.ToInt32()
Nota: lo stesso vale per gli altri metodi citati, vale a dire: Convert.ToInt16(); e Convert.ToInt64();
Esempio 2: int.Parse()
int convertedInt = int.Parse(inputString); // Same result "Input string was not in a correct
format.
Come detto in precedenza, per gestire le eccezioni di solito abbiamo bisogno di un try..catch
come mostrato di seguito:
try
{
https://riptutorial.com/it/home 347
string inputString = "10.2";
int convertedInt = int.Parse(inputString);
}
catch (Exception Ex)
{
//Display some message, that the conversion has failed.
}
Ma usare il try..catch ovunque non sarà una buona pratica, e potrebbero esserci alcuni scenari in
cui vogliamo dare 0 se l'input è sbagliato, (Se seguiamo il metodo sopra, dobbiamo assegnare 0 a
convertedInt da blocco di cattura). Per gestire tali scenari possiamo utilizzare un metodo speciale
chiamato .TryParse() .
Il metodo .TryParse() con una gestione interna delle eccezioni, che fornisce l'output al parametro
out e restituisce un valore booleano che indica lo stato della conversione ( true se la conversione
ha avuto esito positivo, false se non è riuscita). Sulla base del valore di ritorno possiamo
determinare lo stato della conversione. Vediamo un esempio:
Uso 3: senza controllare il valore di ritorno è possibile utilizzare quanto segue, se non si cura del
valore restituito (convertito o meno, 0 sarà ok)
https://riptutorial.com/it/home 348
Capitolo 63: Gestore dell'autenticazione C #
Examples
Gestore di autenticazione
/// <summary>
/// Default overridden method which performs authentication.
/// </summary>
/// <param name="request">Http request message.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Returns http response message of type <see cref="HttpResponseMessage"/>
class asynchronously.</returns>
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Headers.Contains(securityToken))
{
bool authorized = Authorize(request);
if (!authorized)
{
return ApiHttpUtility.FromResult(request, false,
HttpStatusCode.Unauthorized, MessageTypes.Error, Resource.UnAuthenticatedUser);
}
}
else
{
return ApiHttpUtility.FromResult(request, false, HttpStatusCode.BadRequest,
MessageTypes.Error, Resource.UnAuthenticatedUser);
}
/// <summary>
/// Authorize user by validating token.
/// </summary>
/// <param name="requestMessage">Authorization context.</param>
/// <returns>Returns a value indicating whether current request is authenticated or
not.</returns>
private bool Authorize(HttpRequestMessage requestMessage)
{
try
{
HttpRequest request = HttpContext.Current.Request;
string token = request.Headers[securityToken];
return SecurityUtility.IsTokenValid(token, request.UserAgent,
HttpContext.Current.Server.MapPath("~/Content/"), requestMessage);
}
catch (Exception)
https://riptutorial.com/it/home 349
{
return false;
}
}
}
https://riptutorial.com/it/home 350
Capitolo 64: getto
Osservazioni
La trasmissione non è la stessa cosa di Conversione . È possibile convertire il valore di stringa "-
1" in un valore intero ( -1 ), ma ciò deve essere eseguito tramite metodi di libreria come
Convert.ToInt32() o Int32.Parse() . Non può essere fatto usando direttamente la sintassi del cast.
Examples
Trasmetti un oggetto a un tipo di base
string IMyInterface2.GetName()
{
return "IMyInterface2";
}
}
// Outputs :
// I am : IMyInterface1
// I am : IMyInterface2
https://riptutorial.com/it/home 351
Casting esplicito
Se si sa che un valore è di un tipo specifico, è possibile eseguirlo esplicitamente su quel tipo per
poterlo utilizzare in un contesto in cui è necessario quel tipo.
Se non è possibile eseguire il cast di un value su un int , la seconda riga in questo esempio
genera una InvalidCastException
Se non sei sicuro che un valore sia del tipo che pensi di essere, puoi lanciarlo in sicurezza usando
l'operatore as . Se il valore non è di quel tipo, il valore risultante sarà null .
Si noti che null valori null non hanno alcun tipo, quindi la parola chiave as renderà sicuramente
null quando si esegue il cast di qualsiasi valore null .
Casting implicito
Un valore verrà automaticamente convertito nel tipo appropriato se il compilatore sa che può
sempre essere convertito in quel tipo.
In questo esempio, non è stato necessario utilizzare la tipica sintassi di trasmissione esplicita
perché il compilatore sa che tutti gli int possono essere trasmessi agli object s. In effetti,
potremmo evitare di creare variabili e passare -1 direttamente come argomento di
Console.WriteLine() che si aspetta un object .
Console.WriteLine(-1);
https://riptutorial.com/it/home 352
Se è necessario sapere se il tipo di un valore estende o implementa un determinato tipo, ma non
si desidera eseguire effettivamente il cast come quel tipo, è possibile utilizzare l'operatore is .
if(value is int)
{
Console.WriteLine(value + "is an int");
}
Gli operatori di casting espliciti possono essere utilizzati per eseguire conversioni di tipi numerici,
anche se non si estendono o si implementano a vicenda.
Si noti che nei casi in cui il tipo di destinazione ha meno precisione rispetto al tipo originale, la
precisione andrà persa. Ad esempio, -1.1 come valore doppio nell'esempio precedente diventa -1
come valore intero.
Inoltre, le conversioni numeriche si basano sui tipi in fase di compilazione, quindi non
funzioneranno se i tipi numerici sono stati "incapsulati" in oggetti.
Operatori di conversione
Se volessimo creare un JsExpression che rappresenti un confronto tra due valori JavaScript,
potremmo fare qualcosa del genere:
https://riptutorial.com/it/home 353
JsExpression intExpression = new JsExpression("-1");
JsExpression doubleExpression = new JsExpression("-1.0");
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
// Usage:
JsExpression intExpression = (JsExpression)(-1);
JsExpression doubleExpression = (JsExpression)(-1.0);
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Oppure, potremmo cambiare questi operatori in implicito per rendere la sintassi molto più
semplice.
// Usage:
JsExpression intExpression = -1;
Console.WriteLine(intExpression.IsEqualTo(-1.0)); // (-1 == -1.0)
interface IThing { }
class Thing : IThing { }
LINQ consente di creare una proiezione che modifica il tipo generico in fase di compilazione di un
oggetto IEnumerable<> tramite i metodi di estensione Enumerable.Cast<>() ed Enumerable.OfType<>() .
Quando viene valutato things2 , il metodo Cast<>() proverà a things2 tutti i valori nelle things in
Thing s. Se incontra un valore che non può essere lanciato, verrà lanciata una
https://riptutorial.com/it/home 354
InvalidCastException .
Quando viene valutato things3 , il OfType<>() farà lo stesso, eccetto che se incontra un valore che
non può essere lanciato, semplicemente ometterà quel valore anziché lanciare un'eccezione.
A causa del tipo generico di questi metodi, non possono richiamare operatori di conversione o
eseguire conversioni numeriche.
https://riptutorial.com/it/home 355
Capitolo 65: guid
introduzione
GUID (o UUID) è l'acronimo di "Globally Unique Identifier" (o "Universalally Identifier"). È un
numero intero a 128 bit utilizzato per identificare le risorse.
Osservazioni
Guid s sono identificatori univoci globali, noto anche come UUID s', uuid.
Sono valori pseudocasuali a 128 bit. Ci sono così tanti validi Guid (circa 10 ^ 18 Guid per ogni
cellula di ogni popolo sulla Terra) che se sono generati da un buon algoritmo pseudocasuale,
possono essere considerati unici nell'intero universo con tutti i mezzi pratici.
Guidvengono spesso utilizzate come chiavi primarie nei database. Il loro vantaggio è che non è
necessario chiamare il database per ottenere un nuovo ID che è (quasi) garantito come univoco.
Examples
Ottenere la rappresentazione stringa di un Guid
Una rappresentazione in formato stringa di una guida può essere ottenuta utilizzando il metodo
ToString incorporato
A seconda delle esigenze, è inoltre possibile formattare il Guid, aggiungendo un argomento del
tipo di formato alla chiamata ToString .
// None "7febf16f651b43b0a5e30da8da49e90d"
Console.WriteLine(guid.ToString("N"));
// Hyphens "7febf16f-651b-43b0-a5e3-0da8da49e90d"
Console.WriteLine(guid.ToString("D"));
// Braces "{7febf16f-651b-43b0-a5e3-0da8da49e90d}"
Console.WriteLine(guid.ToString("B"));
// Parentheses "(7febf16f-651b-43b0-a5e3-0da8da49e90d)"
Console.WriteLine(guid.ToString("P"));
// Hex "{0x7febf16f,0x651b,0x43b0{0xa5,0xe3,0x0d,0xa8,0xda,0x49,0xe9,0x0d}}"
Console.WriteLine(guid.ToString("X"));
https://riptutorial.com/it/home 356
Questi sono i modi più comuni per creare un'istanza di Guid:
Guid g = Guid.Empty;
Guid g2 = new Guid();
Guid g = Guid.NewGuid();
Come altri tipi di valore, anche il GUID ha un tipo nullable che può assumere valore nullo.
Dichiarazione:
Ciò è particolarmente utile quando si recuperano dati dal database quando esiste la possibilità che
il valore di una tabella sia NULL.
https://riptutorial.com/it/home 357
Capitolo 66: I delegati
Osservazioni
Sommario
Un tipo delegato è un tipo che rappresenta una particolare firma del metodo. Un'istanza di questo
tipo si riferisce a un metodo particolare con una firma corrispondente. I parametri del metodo
possono avere tipi delegati e quindi questo metodo deve essere passato un riferimento a un altro
metodo, che può quindi essere invocato
Func rappresenta i metodi con un tipo di ritorno che corrisponde a TResult e Action rappresenta i
metodi senza un valore di ritorno (void). In entrambi i casi, i parametri di tipo generico aggiuntivi
corrispondono, in ordine, ai parametri del metodo.
Invocazione di delegati
I delegati possono essere richiamati usando la stessa sintassi dei metodi: il nome dell'istanza
delegata, seguito da parentesi contenenti qualsiasi parametro.
Assegnazione ai delegati
I delegati possono essere assegnati nei seguenti modi:
https://riptutorial.com/it/home 358
Combinare i delegati
Più oggetti delegati possono essere assegnati a un'istanza delegata utilizzando l'operatore + .
L'operatore - può essere utilizzato per rimuovere un componente delegato da un altro delegato.
Examples
Riferimenti sottostanti dei delegati del metodo denominato
Quando si assegnano metodi denominati a delegati, si riferiscono allo stesso oggetto sottostante
se:
// ...
Console.WriteLine(instance1.Equals(instance2)); // False
Console.WriteLine(instance1.Equals(instance1Again)); // True
Console.WriteLine(@static.Equals(staticAgain)); // True
La seguente sintassi crea un tipo delegate con nome NumberInOutDelegate , che rappresenta un
metodo che accetta un int e restituisce un int .
https://riptutorial.com/it/home 359
Questo può essere usato come segue:
L' example esempio delegato è eseguito nello stesso modo del Square metodo. Un'istanza delegata
funge letteralmente da delegato per il chiamante: il chiamante richiama il delegato, quindi il
delegato chiama il metodo di destinazione. Questo indiretto disaccoppia il chiamante dal metodo
di destinazione.
È possibile dichiarare un tipo di delegato generico e in tal caso è possibile specificare che il tipo è
covariant ( out ) o controvariante ( in ) in alcuni argomenti di tipo. Per esempio:
Come altri tipi generici, i tipi di delegati generici possono avere vincoli, come nel where TFrom :
struct, IConvertible where TTo : new() .
Evitare la co- e la contravarianza per i tipi di delegati che devono essere utilizzati per i delegati
multicast, come i tipi di gestori di eventi. Questo perché la concatenazione ( + ) può fallire se il tipo
di runtime è diverso dal tipo in fase di compilazione a causa della varianza. Ad esempio, evitare:
https://riptutorial.com/it/home 360
Sono supportati anche i delegati in cui alcuni parametri sono modificati da ref o out , come in:
Il namespace System contiene Func<..., TResult> tipi di delegati con tra 0 e 15 parametri generici,
restituendo il tipo TResult .
Il namespace System contiene anche i tipi di Action<...> delegate con un numero diverso di
parametri generici (da 0 a 16). È simile a Func<T1, .., Tn> , ma restituisce sempre void .
Predicate<T> è anche una forma di Func ma restituirà sempre bool . Un predicato è un modo per
specificare un criterio personalizzato. A seconda del valore dell'input e della logica definita
all'interno del predicato, restituirà true o false . Predicate<T> si comporta quindi allo stesso modo di
Func<T, bool> ed entrambi possono essere inizializzati e utilizzati allo stesso modo.
https://riptutorial.com/it/home 361
var funcReturnsTrue = func("abc");
In aggiunta a ciò, ci sono alcuni casi in cui è disponibile solo una delle opzioni, specialmente
quando si interagisce con un'altra API. Ad esempio, List<T> e Array<T> genere accettano
Predicate<T> per i loro metodi, mentre la maggior parte delle estensioni LINQ accettano solo
Func<T, bool> .
I metodi con nome possono essere assegnati ai delegati con firme corrispondenti:
Delegare l'uguaglianza
Console.WriteLine(action1.Equals(action1)) // True
Console.WriteLine(action1.Equals(action2)) // False
Console.WriteLine(action1Again.Equals(action1)) // True
https://riptutorial.com/it/home 362
Lambdas può essere utilizzato per creare metodi anonimi da assegnare a un delegato:
Si noti che la dichiarazione esplicita di tipo è richiesta quando si crea una variabile in questo
modo:
class FuncAsParameters
{
public void Run()
{
DoSomething(ErrorHandler1);
DoSomething(ErrorHandler2);
}
https://riptutorial.com/it/home 363
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace DelegatesExample {
class MainClass {
private delegate void MyDelegate(int a);
// Output:
// 1
d1(1);
// Output:
// System.Int32
d2(1);
MyDelegate d3 = d1 + d2;
// Output:
// 1
// System.Int32
d3(1);
MyDelegate d4 = d3 - d2;
// Output:
// 1
d4(1);
// Output:
// True
Console.WriteLine(d1 == d4);
}
}
}
class Program
https://riptutorial.com/it/home 364
{
public delegate int Transformer(int x);
t(2) chiamerà prima Square e poi Cube . Il valore di ritorno di Square viene scartato e restituisce il
valore dell'ultimo metodo, ovvero Cube viene mantenuto.
Hai mai desiderato chiamare un delegato multicast ma vuoi che venga chiamato l'intero elenco di
invocazioni anche se si verifica un'eccezione in una catena qualsiasi. Quindi sei fortunato, ho
creato un metodo di estensione che fa proprio questo, lanciando un AggregateException solo dopo
che l'esecuzione dell'intero elenco è stata completata:
if(exceptions.Any())
{
throw new AggregateException(exceptions);
}
}
}
https://riptutorial.com/it/home 365
delegateInstance += this.Target1;
try
{
delegateInstance.SafeInvoke();
}
catch(AggregateException ex)
{
// Do any exception handling here
}
}
Questo produce:
Target 2 executed
Target 1 executed
Chiusura in un delegato
Le chiusure sono metodi anonimi incorporati che hanno la possibilità di utilizzare le variabili del
metodo Parent e altri metodi anonimi che sono definiti nell'ambito del genitore.
https://riptutorial.com/it/home 366
Incapsulando trasformazioni in funzioni
//or this:
if(DateIsValid(this)){
CallAnotherMethod();
}
}
}
Nello spirito di una codifica pulita, l'incapsulamento di verifiche e trasformazioni come quella di cui
sopra come Func può facilitare la lettura e la comprensione del codice. Mentre l'esempio sopra è
molto semplice, e se ci fossero più proprietà DateTime ognuna con le proprie regole di convalida
diverse e volessimo controllare diverse combinazioni? Semplici funzioni di una riga che ciascuna
ha stabilito la logica di ritorno possono essere entrambe leggibili e ridurre l'apparente complessità
del codice. Considera le chiamate di Func qui sotto e immagina quanto più codice ingombrerebbe
il metodo:
https://riptutorial.com/it/home 367
Capitolo 67: ICloneable
Sintassi
• oggetto ICloneable.Clone () {return Clone (); } // Implementazione privata del metodo di
interfaccia che utilizza la nostra funzione pubblica personalizzata Clone ().
• pubblico Foo Clone () {return new Foo (this); } // Il metodo clone pubblico dovrebbe utilizzare
la logica del costruttore di copie.
Osservazioni
Il CLR richiede un object Clone() definizione del metodo object Clone() che non sia sicuro da testo.
È prassi comune sovrascrivere questo comportamento e definire un metodo sicuro per tipo che
restituisce una copia della classe contenente.
Spetta all'autore decidere se la clonazione significa solo copia superficiale o copia profonda. Per
strutture immutabili contenenti riferimenti si consiglia di fare una copia profonda. Poiché le classi
sono riferimenti a se stessi, probabilmente è meglio implementare una copia superficiale.
NOTA: In C# un metodo di interfaccia può essere implementato privatamente con la sintassi mostrata sopra.
Examples
Implementazione ICloneable in una classe
Implementare ICloneable in una classe con una svolta. Esporre un Clone() tipo pubblico sicuro e
implementare l' object Clone() privatamente.
https://riptutorial.com/it/home 368
object ICloneable.Clone()
{
return Clone();
}
#endregion
}
{
Person bob=new Person("Bob", 25);
Person bob_clone=bob.Clone();
Debug.Assert(bob_clone.Name==bob.Name);
bob.Age=56;
Debug.Assert(bob.Age!=bob.Age);
}
Si noti che la modifica dell'età di bob non modifica l'età di bob_clone . Questo perché il design
utilizza la clonazione anziché l'assegnazione di variabili (di riferimento).
L'implementazione di ICloneable per una struttura non è in genere necessaria poiché le strutture
eseguono una copia membro con l'operatore di assegnazione = . Ma il progetto potrebbe
richiedere l'implementazione di un'altra interfaccia che eredita da ICloneable .
Un altro motivo potrebbe essere se la struttura contiene un tipo di riferimento (o un array) che
avrebbe bisogno anche di una copia.
https://riptutorial.com/it/home 369
return Clone();
}
#endregion
}
https://riptutorial.com/it/home 370
Capitolo 68: IComparable
Examples
Ordina versioni
Classe:
Test:
Version a, b;
a = new Version("4.2.1");
b = new Version("4.2.6");
a.CompareTo(b); // a < b : -1
a = new Version("2.8.4");
https://riptutorial.com/it/home 371
b = new Version("2.8.0");
a.CompareTo(b); // a > b : 1
a = new Version("5.2");
b = null;
a.CompareTo(b); // a > b : 1
a = new Version("3");
b = new Version("3.6");
a.CompareTo(b); // a < b : -1
versions.Sort();
Produzione:
NULLO
1
1.0.1
1.1.5
2.0
3.0.10
demo:
https://riptutorial.com/it/home 372
Capitolo 69: Identità ASP.NET
introduzione
Esercitazioni su Asp.net Identity come gestione degli utenti, gestione dei ruoli, creazione di token
e altro.
Examples
Come implementare il token di reimpostazione della password nell'identità di
asp.net utilizzando user manager.
1. Crea una nuova cartella chiamata MyClasses e crea e aggiungi la seguente classe
public GmailEmailService() :
base(ConfigurationManager.AppSettings["GmailHost"],
Int32.Parse(ConfigurationManager.AppSettings["GmailPort"]))
{
//Get values from web.config file:
this.UserName = ConfigurationManager.AppSettings["GmailUserName"];
this.EnableSsl = Boolean.Parse(ConfigurationManager.AppSettings["GmailSsl"]);
this.UseDefaultCredentials = false;
this.Credentials = new System.Net.NetworkCredential(this.UserName,
ConfigurationManager.AppSettings["GmailPassword"]);
}
}
email.IsBodyHtml = true;
3. Aggiungi le tue credenziali a web.config. Non ho usato Gmail in questa parte perché l'utilizzo
di Gmail è bloccato sul mio posto di lavoro e funziona perfettamente.
https://riptutorial.com/it/home 373
<add key="GmailUserName" value="[email protected]"/>
<add key="GmailPassword" value="yourPassword"/>
<add key="GmailHost" value="yourServer"/>
<add key="GmailPort" value="yourPort"/>
<add key="GmailSsl" value="chooseTrueOrFalse"/>
<!--Smptp Server (confirmations emails)-->
https://riptutorial.com/it/home 374
https://riptutorial.com/it/home 375
Compilare quindi eseguire. Saluti!
https://riptutorial.com/it/home 376
Capitolo 70: IEnumerable
introduzione
IEnumerableè l'interfaccia di base per tutte le raccolte non generiche come ArrayList che possono
essere enumerate. IEnumerator<T> è l'interfaccia di base per tutti gli enumeratori generici come
Elenco <>.
Osservazioni
IEnumerable è l'interfaccia di base per tutte le raccolte non generiche che possono essere
enumerate
Examples
IEnumerable
Nella sua forma più elementare, un oggetto che implementa IEnumerable rappresenta una serie di
oggetti. Gli oggetti in questione possono essere iterati utilizzando la parola chiave c foreach .
• Utilizzo di intervalli di numeri basati su una funzione anziché su una raccolta di oggetti
• Implementazione di algoritmi di iterazione diversi su raccolte, come DFS o BFS su una
raccolta di grafici
https://riptutorial.com/it/home 377
public static void Main(string[] args) {
public CoffeeCollection() {
enumerator = new CoffeeEnumerator();
}
return false;
}
https://riptutorial.com/it/home 378
Capitolo 71: ILGenerator
Examples
Crea un DynamicAssembly che contiene un metodo di supporto
UnixTimestamp
Questo esempio mostra l'utilizzo di ILGenerator generando codice che fa uso di membri già
esistenti e nuovi creati oltre alla gestione di base delle eccezioni. Il codice seguente emette un
DynamicAssembly che contiene un equivalente a questo codice c #:
https://riptutorial.com/it/home 379
var dynType = dynMod.DefineType("UnixTimeHelper",
TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public);
var cctor =
dynType.DefineConstructor(
MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName | MethodAttributes.Static, CallingConventions.Standard,
Type.EmptyTypes);
https://riptutorial.com/it/home 380
dynType.CreateType();
dynAsm.Save(an.Name + ".dll");
Questo esempio mostra come sovrascrivere il metodo ToString nella classe generata
https://riptutorial.com/it/home 381
Capitolo 72: Immutabilità
Examples
Classe System.String
In C # (e .NET) una stringa è rappresentata dalla classe System.String. La parola chiave string è
un alias per questa classe.
La classe System.String è immutabile, ovvero una volta creato il suo stato non può essere
modificato.
Quindi tutte le operazioni eseguite su una stringa come Substring, Remove, Replace,
concatenation usando + operatore etc creeranno una nuova stringa e la restituiranno.
Archi e immutabilità
I tipi immutabili sono tipi che, una volta modificati, creano una nuova versione dell'oggetto in
memoria, anziché modificare l'oggetto esistente nella memoria. L'esempio più semplice di questo
è il tipo di string incorporato.
Ciò che sta accadendo in memoria in questo caso è che un nuovo oggetto viene creato quando si
aggiunge alla string nella seconda riga. Se si esegue questa operazione come parte di un loop di
grandi dimensioni, è possibile che ciò causi problemi di prestazioni nell'applicazione.
https://riptutorial.com/it/home 382
Leggi Immutabilità online: https://riptutorial.com/it/csharp/topic/1863/immutabilita
https://riptutorial.com/it/home 383
Capitolo 73: Implementazione del modello di
design Flyweight
Examples
Implementazione della mappa nel gioco RPG
Il peso piuma è uno dei modelli di progettazione strutturale. Viene utilizzato per ridurre la quantità
di memoria utilizzata condividendo il maggior numero possibile di dati con oggetti simili. Questo
documento ti insegnerà come usare correttamente Flyweight DP.
Lascia che ti spieghi l'idea su un semplice esempio. Immagina di lavorare su un gioco di ruolo e
devi caricare un file enorme contenente alcuni personaggi. Per esempio:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@############@@@@@######@#$@@@
@#############@@@######@###@@@
@#######%######@###########@@@
@############################@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Poiché questi oggetti hanno caratteristiche simili, non è necessario creare oggetti separati per
ogni campo mappa. Ti mostrerò come usare il peso mosca.
Ora possiamo creare classi che rappresentano i nostri campi. Dobbiamo anche identificarli in
qualche modo (ho usato un'enumerazione):
https://riptutorial.com/it/home 384
public enum FieldType
{
GRASS,
ROCK,
START,
CHEST
}
public class Grass : IField
{
public string Name { get { return "Grass"; } }
public char Mark { get { return '#'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.GRASS; } }
}
public class StartingPoint : IField
{
public string Name { get { return "Starting Point"; } }
public char Mark { get { return '$'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.START; } }
}
public class Rock : IField
{
public string Name { get { return "Rock"; } }
public char Mark { get { return '@'; } }
public bool CanWalk { get { return false; } }
public FieldType Type { get { return FieldType.ROCK; } }
}
public class TreasureChest : IField
{
public string Name { get { return "Treasure Chest"; } }
public char Mark { get { return '%'; } }
public bool CanWalk { get { return true; } } // you can approach it
public FieldType Type { get { return FieldType.CHEST; } }
}
Come ho detto, non è necessario creare un'istanza separata per ogni campo. Dobbiamo creare un
repository di campi. L'essenza di Flyweight DP è che creiamo dinamicamente un oggetto solo se
ne abbiamo bisogno e non esiste ancora nel nostro repository, o lo restituiamo se già esiste.
Scriviamo una semplice lezione che gestirà questo per noi:
https://riptutorial.com/it/home 385
}
public IField GetField(FieldType type)
{
IField f = lstFields.Find(x => x.Type == type);
if (f != null) return f;
else return AddField(type);
}
}
Ma perché l'erba appare solo una volta se volevamo ottenerla due volte? Questo perché la prima
volta che chiamiamo l'istanza di erba di GetField non esiste nel nostro repository , quindi è stato
creato, ma la prossima volta che abbiamo bisogno di erba esiste già, quindi lo restituiamo solo.
https://riptutorial.com/it/home 386
Capitolo 74: Implementazione del pattern di
progettazione di Decorator
Osservazioni
A favore dell'utilizzo di Decorator:
Examples
Simulazione della caffetteria
Decoratore è uno dei modelli di progettazione strutturale. È usato per aggiungere, rimuovere o
modificare il comportamento dell'oggetto. Questo documento ti insegnerà come usare Decorator
DP correttamente.
Lascia che ti spieghi l'idea su un semplice esempio. Immagina di essere a Starbobs, famosa
compagnia di caffè. È possibile effettuare un ordine per qualsiasi caffè desiderato - con panna e
zucchero, con panna e farcitura e molte altre combinazioni! Ma la base di tutte le bevande è il
caffè - bevanda scura e amara, che puoi modificare. Scriviamo un semplice programma che
simula la macchina del caffè.
Innanzitutto, dobbiamo creare e astrarre una classe che descriva la nostra bevanda di base:
public AbstractCoffee(AbstractCoffee k)
{
this.k = k;
}
Ora, creiamo degli extra, come lo zucchero, il latte e il topping. Le classi create devono
implementare AbstractCoffee - lo decoreranno:
https://riptutorial.com/it/home 387
if (k != null)
return k.ShowCoffee() + " with Milk";
else return "Milk";
}
}
public class Sugar : AbstractCoffee
{
public Sugar(AbstractCoffee c) : base(c) { }
}
}
https://riptutorial.com/it/home 388
Capitolo 75: Implementazione di Singleton
Examples
Singleton inizializzato staticamente
Questa implementazione è thread-safe perché in questo caso l'oggetto instance viene inizializzato
nel costruttore statico. Il CLR garantisce già che tutti i costruttori statici siano eseguiti thread-safe.
L' instance mutante non è un'operazione thread-safe, pertanto l'attributo readonly garantisce
l'immutabilità dopo l'inizializzazione.
Questa versione thread-safe di un singleton era necessaria nelle prime versioni di .NET in cui
l'inizializzazione static non era garantita per essere thread-safe. Nelle versioni più moderne del
framework di solito viene preferito un singleton inizializzato staticamente perché è molto facile
commettere errori di implementazione nel seguente schema.
private ThreadSafeSingleton()
{
}
return instance;
}
https://riptutorial.com/it/home 389
}
}
Si noti che il controllo if (instance == null) viene eseguito due volte: una volta prima
dell'acquisizione del blocco e una volta in seguito. Questa implementazione sarebbe ancora
thread-safe anche senza il primo controllo nullo. Tuttavia, ciò significherebbe che un blocco
sarebbe acquisito ogni volta che viene richiesta l'istanza, e ciò causerebbe sofferenza alle
prestazioni. Il primo controllo nullo viene aggiunto in modo tale che il blocco non venga acquisito a
meno che non sia necessario. Il secondo controllo nullo si assicura che solo il primo thread per
acquisire il blocco crei l'istanza. Gli altri thread troveranno l'istanza da compilare e saltare in
avanti.
.Net 4.0 type Lazy garantisce l'inizializzazione degli oggetti thread-safe, quindi questo tipo
potrebbe essere usato per creare Singletons.
private LazySingleton() { }
}
Usando Lazy<T> ci si assicurerà che l'oggetto sia istanziato solo quando è usato da qualche parte
nel codice chiamante.
using System;
Perché in .NET 3.5 e versioni precedenti non hai la classe Lazy<T> tu usi il seguente modello:
https://riptutorial.com/it/home 390
public class Singleton
{
private Singleton() // prevents public instantiation
{
}
Poiché la classe Nested è nidificata e privata, l'istanza dell'istanza singleton non verrà attivata
accedendo ad altri membri della classe Sigleton (ad esempio, una proprietà pubblica di sola
lettura, ad esempio).
private LazySingleton() { }
https://riptutorial.com/it/home 391
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
if (--_instanceCount == 0) // No more references to this object.
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
if (disposing)
{
_instance = null; // Allow GC to dispose of this instance.
// Free any other managed objects here.
}
https://riptutorial.com/it/home 392
Capitolo 76: Importa contatti Google
Osservazioni
I dati dei contatti dell'utente saranno ricevuti in formato JSON, lo estraiamo e finalmente passiamo
in rassegna questi dati e otteniamo così i contatti di Google.
Examples
Requisiti
Per importare i contatti di Google (Gmail) nell'applicazione ASP.NET MVC, devi prima scaricare
"Impostazione dell'API di Google". Ciò consentirà i seguenti riferimenti:
using Google.Contacts;
using Google.GData.Client;
using Google.GData.Contacts;
using Google.GData.Extensions;
using Google.Contacts;
using Google.GData.Client;
using Google.GData.Contacts;
using Google.GData.Extensions;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace GoogleContactImport.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
https://riptutorial.com/it/home 393
redirectUrl + "&&response_type=code&&client_id=" + clientId +
"&&scope=https://www.google.com/m8/feeds/&approval_prompt=force&access_type=offline");
return View();
}
HttpWebRequest webRequest =
(HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
webRequest.Method = "POST";
string parameters = "code=" + code + "&client_id=" + google_client_id +
"&client_secret=" + google_client_sceret + "&redirect_uri=" + google_redirect_url +
"&grant_type=authorization_code";
byte[] byteArray = Encoding.UTF8.GetBytes(parameters);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = byteArray.Length;
Stream postStream = webRequest.GetRequestStream();
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
WebResponse response = webRequest.GetResponse();
postStream = response.GetResponseStream();
StreamReader reader = new StreamReader(postStream);
string responseFromServer = reader.ReadToEnd();
GooglePlusAccessToken serStatus =
JsonConvert.DeserializeObject<GooglePlusAccessToken>(responseFromServer);
/*End*/
return GetContacts(serStatus);
}
https://riptutorial.com/it/home 394
string google_client_sceret = ""; //secret key
/*Get Google Contacts From Access Token and Refresh Token*/
// string refreshToken = serStatus.refresh_token;
string accessToken = serStatus.access_token;
string scopes = "https://www.google.com/m8/feeds/contacts/default/full/";
OAuth2Parameters oAuthparameters = new OAuth2Parameters()
{
ClientId = google_client_id,
ClientSecret = google_client_sceret,
RedirectUri = "http://localhost:1713/Home/AddGoogleContacts",
Scope = scopes,
AccessToken = accessToken,
// RefreshToken = refreshToken
};
public GooglePlusAccessToken()
{ }
https://riptutorial.com/it/home 395
{
get { return _token_type; }
set { _token_type = value; }
}
private string _token_type;
}
}
}
L'unico metodo di azione che devi aggiungere è aggiungere un link di azione presente sotto
https://riptutorial.com/it/home 396
Capitolo 77: indicizzatore
Sintassi
• public ReturnType this [IndexType index] {ottieni {...} set {...}}
Osservazioni
Indexer consente la sintassi di tipo array per accedere a una proprietà di un oggetto con un indice.
Examples
Un semplice indicizzatore
class Foo
{
private string[] cities = new[] { "Paris", "London", "Berlin" };
Uso:
// access a value
string berlin = foo[2];
// assign a value
foo[0] = "Rome";
Visualizza la demo
https://riptutorial.com/it/home 397
interface ITable {
// an indexer can be declared in an interface
object this[int x, int y] { get; set; }
}
/// <summary>
/// implementation of the indexer declared in the interface
/// </summary>
/// <param name="x">X-Index</param>
/// <param name="y">Y-Index</param>
/// <returns>Content of this cell</returns>
public object this[int x, int y]
{
get
{
return cells[x, y];
}
set
{
cells[x, y] = value;
}
}
}
class SparseArray
{
Dictionary<int, string> array = new Dictionary<int, string>();
https://riptutorial.com/it/home 398
Leggi indicizzatore online: https://riptutorial.com/it/csharp/topic/1660/indicizzatore
https://riptutorial.com/it/home 399
Capitolo 78: Iniezione di dipendenza
Osservazioni
La definizione di Wikipedia di iniezione di dipendenza è:
** Questo sito offre una risposta alla domanda Come spiegare l'iniezione di dipendenza a
un bambino di 5 anni. La risposta più votata, fornita da John Munsch, fornisce un'analogia
sorprendentemente precisa rivolta al (immaginario) inquisitore quinquennale: quando vai a
prendere le cose dal frigorifero per conto tuo, puoi causare problemi. Potresti lasciare la
porta aperta, potresti ottenere qualcosa che mamma o papà non vogliono che tu abbia.
Potresti anche cercare qualcosa che non abbiamo nemmeno o che è scaduto. Quello che
dovresti fare è affermare un bisogno, "Ho bisogno di qualcosa da bere a pranzo", e poi ci
assicureremo che tu abbia qualcosa quando ti siedi per mangiare. Cosa significa in termini
di sviluppo di software orientato agli oggetti è questo: le classi collaborative (i bambini di
cinque anni) dovrebbero fare affidamento sull'infrastruttura (i genitori) per fornire
** Questo codice utilizza MEF per caricare dinamicamente la dll e risolvere le dipendenze. La
dipendenza di ILogger è risolta da MEF e iniettata nella classe utente. La classe utente non riceve
mai l'implementazione concreta di ILogger e non ha idea di quale tipo di registratore utilizzi. **
Examples
Iniezione delle dipendenze con MEF
[Export(typeof(ILogger))]
[ExportMetadata("Name", "Console")]
public class ConsoleLogger:ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
[Export(typeof(ILogger))]
[ExportMetadata("Name", "File")]
public class FileLogger:ILogger
{
https://riptutorial.com/it/home 400
public void Log(string message)
{
//Write the message to file
}
}
[ImportMany]
private IEnumerable<Lazy<ILogger, ILoggerMetaData>> _loggers;
https://riptutorial.com/it/home 401
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
throw new CompositionException(compositionException.Message);
}
}
}
Innanzitutto perché dovremmo usare l'iniezione di depedency nel nostro codice? Vogliamo
disaccoppiare altri componenti da altre classi nel nostro programma. Ad esempio abbiamo
AnimalController di classe che hanno un codice come questo:
public AnimalController(){
Console.WriteLine("");
}
}
Guardiamo questo codice e pensiamo che tutto sia a posto, ma ora il nostro AnimalController
dipende dall'oggetto _SantaAndHisReindeer. Automaticamente il mio controller non è adatto ai
test e la riusabilità del mio codice sarà molto difficile.
Ottima spiegazione del motivo per cui dovremmo usare Injection e interfacce qui .
Se vogliamo che Unity gestisca DI, la strada per raggiungerla è molto semplice :) Con NuGet
(gestore pacchetti) possiamo facilmente importare unità nel nostro codice.
in Visual Studio Tools -> NuGet Package Manager -> Gestisci pacchetti per soluzione -
> in input di ricerca scrivi unità -> scegli il nostro progetto-> fai clic su Installa
UnityConfig - nel metodo RegisterTypes, possiamo vedere il tipo che verrà inserito nei
nostri costruttori.
namespace Vegan.WebUi.App_Start
{
https://riptutorial.com/it/home 402
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
container.RegisterType<ISanta, SantaAndHisReindeer>();
}
}
}
UnityMvcActivator -> anche con dei bei commenti che dicono che questa classe
integra Unity con ASP.NET MVC
using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
[assembly:
WebActivatorEx.PreApplicationStartMethod(typeof(Vegan.WebUi.App_Start.UnityWebActivator),
"Start")]
[assembly:
WebActivatorEx.ApplicationShutdownMethod(typeof(Vegan.WebUi.App_Start.UnityWebActivator),
"Shutdown")]
namespace Vegan.WebUi.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().Firs
https://riptutorial.com/it/home 403
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
}
_SantAndHisReindeer = SantaAndHisReindeer;
}
}
C'è un'ultima cosa che dobbiamo fare prima di eseguire la nostra applicazione.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Vegan.WebUi.App_Start;
namespace Vegan.WebUi
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityWebActivator.Start();
}
}
https://riptutorial.com/it/home 404
}
https://riptutorial.com/it/home 405
Capitolo 79: Inizializzatori di oggetti
Sintassi
• SomeClass sc = new SomeClass {Property1 = value1, Property2 = value2, ...};
• SomeClass sc = new SomeClass (param1, param2, ...) {Proprietà1 = valore1, Proprietà2 =
valore2, ...}
Osservazioni
Le parentesi del costruttore possono essere omesse solo se il tipo istanziato ha un costruttore
predefinito (senza parametri) disponibile.
Examples
Uso semplice
Gli inizializzatori degli oggetti sono utili quando è necessario creare un oggetto e impostare subito
un paio di proprietà, ma i costruttori disponibili non sono sufficienti. Di 'che hai una lezione
Book theBook = new Book { Title = "Don Quixote", Author = "Miguel de Cervantes" };
Questo è equivalente a
Gli inizializzatori degli oggetti sono l'unico modo per inizializzare i tipi anonimi, che sono tipi
generati dal compilatore.
Per questo motivo gli inizializzatori di oggetti sono ampiamente utilizzati nelle query di selezione
https://riptutorial.com/it/home 406
LINQ, poiché forniscono un modo conveniente per specificare quali parti di un oggetto interrogato
sono interessati.
È possibile combinare gli inizializzatori di oggetti con i costruttori per inizializzare i tipi, se
necessario. Prendiamo ad esempio una classe definita come tale:
var someBook = new Book(16) { Title = "Don Quixote", Author = "Miguel de Cervantes" }
Ciò prima istanzia un costruttore Book with the Book(int) , quindi imposta ogni proprietà
nell'inizializzatore. È equivalente a:
https://riptutorial.com/it/home 407
Capitolo 80: Inizializzatori di raccolta
Osservazioni
L'unico requisito per l'inizializzazione di un oggetto utilizzando questo zucchero sintattico è che il
tipo implementa System.Collections.IEnumerable e il metodo Add . Sebbene lo chiamiamo
inizializzatore di una raccolta, l'oggetto non deve essere una raccolta.
Examples
Inizializzatori di raccolta
Gli inizializzatori della raccolta sono zucchero sintattico per le chiamate Add() . Sopra il codice è
equivalente a:
Si noti che l'intializzazione viene eseguita atomicamente utilizzando una variabile temporanea, per
evitare condizioni di competizione.
Per i tipi che offrono più parametri nel loro metodo Add() , racchiudi gli argomenti separati da
virgola in parentesi graffe:
Questo è equivalente a:
https://riptutorial.com/it/home 408
Inizializzatori dell'indice C # 6
Questo è equivalente a:
La sintassi di inizializzazione della raccolta per eseguire questa operazione prima di C # 6 era:
Quale corrisponderebbe a:
Quindi c'è una differenza significativa nella funzionalità, poiché la nuova sintassi usa l'
indicizzatore dell'oggetto inizializzato per assegnare valori invece di usare il suo metodo Add() .
Ciò significa che la nuova sintassi richiede solo un indicizzatore pubblicamente disponibile e
funziona per qualsiasi oggetto che ne ha uno.
https://riptutorial.com/it/home 409
}
Ciò produrrebbe:
Per creare un inizializzatore della raccolta del supporto classe, deve implementare l'interfaccia
IEnumerable e avere almeno un metodo Add . Dal momento che C # 6, qualsiasi raccolta attuare
IEnumerable può essere esteso con personalizzati Add metodi che utilizzano metodi di estensione.
class Program
{
static void Main()
{
var col = new MyCollection {
"foo",
{ "bar", 3 },
"baz",
123.45d,
};
}
}
https://riptutorial.com/it/home 410
}
Synonyms è una proprietà del tipo di raccolta. Quando l'oggetto Tag viene creato utilizzando la
sintassi di inizializzazione dell'oggetto, i Synonyms possono anche essere inizializzati con la sintassi
di inizializzazione della raccolta:
La proprietà della raccolta può essere in sola lettura e supporta ancora la sintassi di
inizializzazione della raccolta. Considera questo esempio modificato (la proprietà Synonyms ora ha
un setter privato):
https://riptutorial.com/it/home 411
}
Funziona perché gli inizializzatori della raccolta sono solo zucchero sintattico sulle chiamate a
Add() . Non è stato creato alcun nuovo elenco qui, il compilatore sta solo generando chiamate a
Add() sull'oggetto che sta uscendo.
https://riptutorial.com/it/home 412
Capitolo 81: Inizializzazione delle proprietà
Osservazioni
Al momento di decidere come creare una proprietà, iniziare con una proprietà auto-implementata
per semplicità e brevità.
Passa a una proprietà con un campo di supporto solo quando le circostanze lo richiedono. Se hai
bisogno di altre manipolazioni oltre un semplice set e ottieni, potresti dover introdurre un backing
field.
Examples
C # 6.0: inizializzazione di una proprietà implementata automaticamente
Crea una proprietà con getter e / o setter e inizializza tutto in una riga:
class Example
{
public string Foobar { get; set; }
public List<string> Names { get; set; }
public Example()
{
Foobar = "xyz";
Names = new List<string>(){"carrot","fox","ball"};
}
}
https://riptutorial.com/it/home 413
Year = 2016,
Color = Color.Red
};
https://riptutorial.com/it/home 414
Capitolo 82: interfacce
Examples
Implementazione di un'interfaccia
Un'interfaccia viene utilizzata per forzare la presenza di un metodo in qualsiasi classe che lo
"implementa". L'interfaccia è definita con l' interface per le parole chiave e una classe può
"implementarla" aggiungendo : InterfaceName dopo il nome della classe. Una classe può
implementare più interfacce separando ciascuna interfaccia con una virgola.
: InterfaceName, ISecondInterface
Poiché implementano INoiseMaker , sia il cat che il dog devono includere il metodo string
MakeNoise() e non potranno compilare senza di esso.
https://riptutorial.com/it/home 415
}
interface IChauffeur
{
string Drive();
}
interface IGolfPlayer
{
string Drive();
}
string IGolfPlayer.Drive()
{
return "Took a swing...";
}
}
Console.WriteLine(obj.Drive()); // Vroom!
Console.WriteLine(chauffeur.Drive()); // Vroom!
Console.WriteLine(golfer.Drive()); // Took a swing...
https://riptutorial.com/it/home 416
{
return "Swinging hard...";
}
public void Swing()
{
Drive(); // Compiler error: No such method
}
}
Un'implementazione esplicita dell'interfaccia può naturalmente essere utilizzata solo per i metodi
effettivamente esistenti per quell'interfaccia:
Allo stesso modo, l'utilizzo di un'implementazione esplicita dell'interfaccia senza dichiarare che
l'interfaccia sulla classe causa anche un errore.
Suggerimento:
Implementare le interfacce in modo esplicito può anche essere usato per evitare il dead code.
Quando un metodo non è più necessario e viene rimosso dall'interfaccia, il compilatore si
lamenterà di ogni implementazione ancora esistente.
Nota:
I programmatori si aspettano che il contratto sia lo stesso indipendentemente dal contesto del tipo
e l'implementazione esplicita non dovrebbe esporre un comportamento diverso quando viene
chiamata. Quindi, a differenza dell'esempio sopra, IGolfPlayer.Drive e Drive dovrebbero fare la
stessa cosa quando possibile.
Diciamo che definiamo un'interfaccia IShape per rappresentare diversi tipi di forme, ci aspettiamo
che una forma abbia un'area, quindi definiremo un metodo per forzare le implementazioni
dell'interfaccia a restituire la loro area:
https://riptutorial.com/it/home 417
public interface IShape
{
double ComputeArea();
}
Ognuno di loro ha la propria definizione della propria area, ma entrambi sono forme. Quindi è
logico vederli come IShape nel nostro programma:
Console.ReadKey();
}
https://riptutorial.com/it/home 418
// Output:
// Area : 50.00
// Area : 78.54
La funzione di un'interfaccia nota come "contratto" di funzionalità. Significa che dichiara proprietà
e metodi ma non li implementa.
Cose da notare:
// ok
obj.TheThingICanDo();
// ok
obj.SomeValueProperty = 5;
// in order to access the property in the class you must "down cast" it
((MyClass)obj).SomeValueNotImplemtingAnything = 5; // ok
https://riptutorial.com/it/home 419
Ciò è particolarmente utile quando si lavora con framework UI come WinForms o WPF perché è
obbligatorio ereditare da una classe base per creare il controllo utente e si perde la possibilità di
creare astrazioni su diversi tipi di controllo. Un esempio? In arrivo:
Il problema proposto è che entrambi contengono un concetto di "Testo" ma i nomi delle proprietà
differiscono. E non puoi creare creare una classe base astratta perché hanno un'eredità
obbligatoria per 2 classi diverse. Un'interfaccia può alleggerirlo
// Runtime Error because 1 class is in fact not a button which makes this cast invalid
((MyButton)ctrl).Clicks = 0;
https://riptutorial.com/it/home 420
This is usually considered bad practice since
it's a symptom of poor abstraction */
var button = ctrl as MyButton;
if(button != null)
button.Clicks = 0; // no errors
Non lo odi quando le interfacce inquinano la tua classe con troppi membri di cui non ti importa
nemmeno? Bene, ho una soluzione! Implementazioni esplicite
Risposta: non lo so Quindi nessuno dei due dovrebbe essere dichiarato pubblico, ma
semplicemente dichiarare i membri come privati farà sì che il compilatore lanci un errore
https://riptutorial.com/it/home 421
void IMessageService.SendMessage() {
Quindi ora hai implementato i membri come richiesto e non espongono alcun membro come
pubblico.
((IMessageService)obj).OnMessageRecieve();
Le interfacce possono sembrare astratte fino a quando non le appari in pratica. I IComparable<T>
IComparable e IComparable<T> sono ottimi esempi del perché le interfacce possono essere utili a noi.
Diciamo che in un programma per un negozio online, abbiamo una varietà di oggetti che puoi
comprare. Ogni articolo ha un nome, un numero identificativo e un prezzo.
public string name; // though public variables are generally bad practice,
public int idNumber; // to keep this example simple we will use them instead
public decimal price; // of a property.
Abbiamo i nostri Item s memorizzati all'interno di un List<Item> e nel nostro programma da qualche
parte, vogliamo ordinare il nostro elenco per numero ID dal più piccolo al più grande. Invece di
scrivere il nostro algoritmo di ordinamento, possiamo invece usare il metodo Sort() che List<T> ha
già. Tuttavia, poiché la nostra classe Item è in questo momento, non c'è modo per List<T> di
capire quale ordine ordinare l'elenco. Qui è dove entra in IComparable interfaccia IComparable .
https://riptutorial.com/it/home 422
apple.idNumber = 15;
Item banana = new Item();
banana.idNumber = 4;
Item cow = new Item();
cow.idNumber = 15;
Item diamond = new Item();
diamond.idNumber = 18;
Console.WriteLine(apple.CompareTo(banana)); // 11
Console.WriteLine(apple.CompareTo(cow)); // 0
Console.WriteLine(apple.CompareTo(diamond)); // -3
https://riptutorial.com/it/home 423
Capitolo 83: Interfaccia IDisposable
Osservazioni
• Spetta ai client della classe che implementano IDisposable per assicurarsi che chiamino il
metodo Dispose quando hanno finito di utilizzare l'oggetto. Non c'è nulla nel CLR che cerca
direttamente oggetti per un metodo Dispose da richiamare.
• Si consiglia di rendere la classe sicura contro più chiamate a Dispose , sebbene dovrebbe
idealmente essere chiamata una sola volta. Questo può essere ottenuto aggiungendo una
variabile private bool alla classe e impostando il valore su true quando è stato eseguito il
metodo Dispose .
Examples
In una classe che contiene solo risorse gestite
Le risorse gestite sono risorse che il garbage collector del runtime è a conoscenza e sotto il
controllo di. Esistono molte classi disponibili nel BCL, ad esempio, come SqlConnection che è una
classe wrapper per una risorsa non gestita. Queste classi implementano già l'interfaccia
IDisposable - IDisposable dal tuo codice per ripulirle quando hai finito.
Non è necessario implementare un finalizzatore se la tua classe contiene solo risorse gestite.
È importante lasciare che la finalizzazione ignori le risorse gestite. Il finalizzatore viene eseguito
su un altro thread: è possibile che gli oggetti gestiti non esistano più al momento dell'esecuzione
del finalizzatore. L'implementazione di un metodo Dispose(bool) protetto Dispose(bool) è una
pratica comune per garantire che le risorse gestite non abbiano il loro metodo Dispose chiamato da
un finalizzatore.
https://riptutorial.com/it/home 424
{
private SqlConnection sqlConnection = new SqlConnection();
private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
private bool disposed;
unmanagedHandle.Release();
disposed = true;
}
}
~ManagedAndUnmanagedObject()
{
Dispose(false);
}
}
IDisposable, Dispose
.NET Framework definisce un'interfaccia per i tipi che richiedono un metodo di rimozione:
Dispose() viene utilizzato principalmente per la pulizia delle risorse, come i riferimenti non gestiti.
Tuttavia, può anche essere utile forzare lo smaltimento di altre risorse anche se sono gestite.
Invece di aspettare che il GC risolva anche la tua connessione al database, puoi assicurarti che
sia fatto nella tua implementazione di Dispose() .
https://riptutorial.com/it/home 425
Quando è necessario accedere direttamente alle risorse non gestite come puntatori non gestiti o
risorse win32, creare una classe ereditata da SafeHandle e utilizzare le convenzioni / gli strumenti
di quella classe per farlo.
È abbastanza comune che sia possibile creare una classe che implementa IDisposable e quindi
derivare classi che contengono anche risorse gestite. Si consiglia di contrassegnare il metodo
Dispose con la parola chiave virtual modo che i client abbiano la possibilità di ripulire tutte le
risorse che possono possedere.
Quando un oggetto implementa l'interfaccia IDisposable , può essere creato all'interno della
sintassi using :
https://riptutorial.com/it/home 426
}
Guarda la demo
usingè zucchero sintetico per un blocco try/finally ; l'utilizzo di cui sopra si tradurrebbe
approssimativamente in:
{
var foo = new Foo();
try
{
// do foo stuff
}
finally
{
if (foo != null)
((IDisposable)foo).Dispose();
}
}
https://riptutorial.com/it/home 427
Capitolo 84: Interfaccia
INotifyPropertyChanged
Osservazioni
L'interfaccia INotifyPropertyChanged è necessaria ogni volta che è necessario per rendere la classe
segnalare le modifiche che si verificano alle sue proprietà. L'interfaccia definisce un singolo
evento PropertyChanged .
Examples
Implementazione di INotifyPropertyChanged in C # 6
class C : INotifyPropertyChanged
{
// backing field
int offset;
// property
public int Offset
{
get
{
return offset;
}
set
{
if (offset == value)
return;
offset = value;
RaisePropertyChanged();
}
}
// interface implemetation
public event PropertyChangedEventHandler PropertyChanged;
}
Se hai diverse classi che implementano INotifyPropertyChanged , potresti trovare utile rifattorizzare
https://riptutorial.com/it/home 428
l'implementazione dell'interfaccia e il metodo helper alla classe base comune:
// interface implemetation
public event PropertyChangedEventHandler PropertyChanged;
}
class C : NotifyPropertyChangedImpl
{
int offset;
public int Offset
{
get { return offset; }
set { if (offset != value) { offset = value; RaisePropertyChanged(); } }
}
}
La classe NotifyPropertyChangedBase seguito definisce un metodo Set generico che può essere
chiamato da qualsiasi tipo derivato.
Per utilizzare questo metodo Set generico, è sufficiente creare una classe che derivi da
NotifyPropertyChangedBase.
https://riptutorial.com/it/home 429
}
Come mostrato sopra, puoi chiamare Set(ref _fieldName, value); nel setter di una proprietà e
genererà automaticamente un evento PropertyChanged se necessario.
È quindi possibile registrarsi all'evento PropertyChanged da un'altra classe che deve gestire le
modifiche alle proprietà.
https://riptutorial.com/it/home 430
Capitolo 85: Interfaccia IQueryable
Examples
Tradurre una query LINQ in una query SQL
Le IQueryable e IQueryable<T> consentono agli sviluppatori di tradurre una query LINQ (una query
"language-integrated") in un'origine dati specifica, ad esempio un database relazionale. Prendi
questa query LINQ scritta in C #:
Il provider può ispezionare l'albero delle espressioni in fase di esecuzione per determinare:
Con queste informazioni il provider può tradurre la query C # in una query SQL in fase di runtime e
passare quella query a un database relazionale per recuperare solo quei libri che corrispondono al
predicato:
select *
from Books
where Author = 'Stephen King'
Il provider viene chiamato quando la variabile di query viene iterata su ( IQueryable implementa
IEnumerable ).
(Il provider utilizzato in questo esempio richiede alcuni metadati aggiuntivi per sapere quale tabella
interrogare e sapere come abbinare le proprietà della classe C # alle colonne della tabella, ma tali
metadati sono al di fuori dell'ambito dell'interfaccia IQueryable .)
https://riptutorial.com/it/home 431
Capitolo 86: interoperabilità
Osservazioni
Lavorare con API Win32 usando C #
Windows espone molte funzionalità sotto forma di API Win32. Usando queste API è possibile
eseguire operazioni dirette in Windows, il che aumenta le prestazioni della tua applicazione.
Source Clicca qui
Windows espone un'ampia gamma di API. Per ottenere informazioni su varie API puoi controllare
siti come pinvoke .
Examples
Funzione di importazione da DLL C ++ non gestita
Ecco un esempio di come importare una funzione definita in una DLL C ++ non gestita. Nel codice
sorgente C ++ per "myDLL.dll", la funzione add è definita:
class Program
{
// This line will import the C++ method.
// The name specified in the DllImport attribute must be the DLL name.
// The names of parameters are unimportant, but the types must be correct.
[DllImport("myDLL.dll")]
private static extern int add(int left, int right);
Vedi Calling convenzioni e manomissione dei nomi in C ++ per spiegazioni sul perché extern "C" e
__stdcall siano necessari.
https://riptutorial.com/it/home 432
Quando viene invocato per la prima volta il metodo extern, il programma C # cercherà e caricherà
la DLL appropriata. Per ulteriori informazioni su dove viene eseguita la ricerca per trovare la DLL e
su come è possibile influenzare le posizioni di ricerca, consultare questa domanda StackOverflow
.
using System;
using System.Runtime.InteropServices;
namespace ComLibrary
{
[ComVisible(true)]
public interface IMainType
{
int GetInt();
void StartTime();
int StopTime();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MainType : IMainType
{
private Stopwatch stopWatch;
Mancanza di nomi in C ++
I compilatori C ++ codificano informazioni aggiuntive nei nomi delle funzioni esportate, come i tipi
di argomenti, per rendere possibili sovraccarichi con argomenti diversi. Questo processo è
chiamato mangling del nome . Ciò causa problemi con l'importazione di funzioni in C # (e
l'interoperabilità con altre lingue in generale), poiché il nome della funzione int add(int a, int b)
non viene più add , può essere ?add@@YAHHH@Z , _add@8 o qualsiasi altra cosa, a seconda del
compilatore e della convenzione di chiamata.
https://riptutorial.com/it/home 433
Esistono diversi modi per risolvere il problema della manomissione dei nomi:
• Esportare funzioni usando extern "C" per passare al collegamento esterno C che utilizza il
nome C mangling:
[DllImport("myDLL.dll")]
Il nome della funzione sarà ancora _add@8 ( _add@8 ), ma StdCall + extern "C" nome mangling
è riconosciuto dal compilatore C #.
• Specifica dei nomi delle funzioni esportate nel file di definizione del modulo myDLL.def :
EXPORTS
add
[DllImport("myDLL.dll")]
• Importazione del nome mutilato. Avrai bisogno di un visualizzatore DLL per vedere il nome
storpiato, quindi puoi specificarlo esplicitamente:
Chiamare convenzioni
Esistono diverse convenzioni delle funzioni di chiamata, che specificano chi (chiamante o
chiamato) apre gli argomenti dallo stack, come vengono passati gli argomenti e in quale ordine. C
++ utilizza la convenzione di chiamata Cdecl per impostazione predefinita, ma C # si aspetta che
StdCall venga utilizzato di solito dalle API di Windows. Devi cambiare uno o l'altro:
[DllImport("myDLL.dll")]
https://riptutorial.com/it/home 434
[DllImport("myDLL.dll", CallingConvention = CallingConvention.Cdecl)]
Se si desidera utilizzare una funzione con convenzione di chiamata Cdecl e un nome storpiato, il
codice sarà simile a questo:
• thiscall ( __thiscall ) è usato principalmente in funzioni che sono membri di una classe.
• Quando una funzione utilizza thiscall ( __thiscall ), un puntatore alla classe viene passato
come primo parametro.
Quando si utilizza l'attributo DllImport è necessario conoscere la dll corretta e il nome del metodo
in fase di compilazione . Se si desidera essere più flessibili e decidere in fase di esecuzione quali
DLL e metodi da caricare, è possibile utilizzare i metodi dell'API di Windows LoadLibrary() ,
GetProcAddress() e FreeLibrary() . Questo può essere utile se la libreria da utilizzare dipende dalle
condizioni di runtime.
class Program
{
// import necessary API as shown in other examples
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string lib);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void FreeLibrary(IntPtr module);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr module, string proc);
https://riptutorial.com/it/home 435
if (method == IntPtr.Zero) // error handling
{
Console.WriteLine($"Could not load method: {Marshal.GetLastWin32Error()}");
FreeLibrary(module); // unload library
return;
}
// use function
int result = add(750, 300);
// unload library
FreeLibrary(module);
}
}
SetLastError = true
SetLastError = false
Indica che il chiamato non chiamerà SetLastError (funzione API Win32), quindi non si otterranno
informazioni di errore.
Esempio:
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr OpenMutex(uint access, bool handle, string lpName);
if (lastErrorCode == (uint)ERROR_FILE_NOT_FOUND)
{
//Deal with error
}
https://riptutorial.com/it/home 436
I codici di errore del sistema possono essere trovati qui:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
API GetLastError
[DllImport("coredll.dll", SetLastError=true)]
static extern Int32 GetLastError();
• Quando si chiama l'API Win32 dal codice gestito, è necessario utilizzare sempre
Marshal.GetLastWin32Error .
Ecco perché:
Tra la chiamata Win32 che imposta l'errore (chiama SetLastError), il CLR può chiamare anche
altre chiamate Win32 che potrebbero chiamare SetLastError , questo comportamento può
ignorare il valore dell'errore. In questo scenario, se si chiama GetLastError è possibile ottenere
un errore non valido.
Impostazione SetLastError = true , assicura che il CLR recuperi il codice di errore prima di
eseguire altre chiamate Win32.
Oggetto appuntato
Mentre GC pulisce la nostra spazzatura, rimuove gli oggetti non utilizzati dall'heap gestito che
causano la frammentazione dell'heap. Quando GC ha terminato la rimozione, esegue una
compressione heap (defragmintation) che implica lo spostamento di oggetti nell'heap.
Dato che GC non è deterministico, quando passa il riferimento / puntatore dell'oggetto gestito al
codice nativo, GC può dare il via in qualsiasi momento, se si verifica subito dopo la chiamata
Inerop, c'è una buona possibilità che l'oggetto (il riferimento passato a nativo) possa essere
spostati sull'heap gestito - di conseguenza, otteniamo un riferimento non valido sul lato gestito.
Oggetto appuntato
Maniglia appuntata Gc
https://riptutorial.com/it/home 437
come uno che non può essere spostato da GC , fino a liberare l'handle
Esempio:
Precauzioni
PtrToStructure generico:
T - tipo di struttura.
Esempio:
• Se hai a che fare con oggetti gestiti durante la lettura di strutture native, non dimenticare di
https://riptutorial.com/it/home 438
appuntare il tuo oggetto :)
T Read<T>(byte[] buffer)
{
T result = default(T);
try
{
result = Marshal.PtrToStructure<T>(gch.AddrOfPinnedObject());
}
finally
{
gch.Free();
}
return result;
}
https://riptutorial.com/it/home 439
Capitolo 87: Interpolazione a stringa
Sintassi
• $ "contenuto {espressione} contenuto"
• $ "contenuto {espressione: formato} contenuto"
• $ "contenuto {espressione} {{contenuto in parentesi}} contenuto}"
• $ "contenuto {espressione: formato} {{contenuto in parentesi}} contenuto}"
Osservazioni
L'interpolazione delle stringhe è una scorciatoia per il metodo string.Format() che semplifica la
creazione di stringhe con valori di variabili ed espressioni al loro interno.
Examples
espressioni
È inoltre possibile utilizzare il metodo DateTime.ToString per formattare l'oggetto DateTime . Questo
produrrà lo stesso risultato del codice sopra.
Produzione:
https://riptutorial.com/it/home 440
È l'11 novembre 2015, esprimi un desiderio!
Nota: MM indica mesi e mm per minuti. Fai molta attenzione quando li usi, perché gli
errori possono introdurre bug che potrebbero essere difficili da scoprire.
Uso semplice
Dietro le quinte
Internamente questo
$"Hello, {name}!"
Riempimento dell'output
${value, padding}
Padding sinistro
Una spaziatura a sinistra di 5 (aggiunge 3 spazi prima del valore del numero, quindi occupa un
totale di 5 posizioni di carattere nella stringa risultante).
Produzione:
https://riptutorial.com/it/home 441
The answer to life, the universe and everything is 42.
Imbottitura a destra
Il riempimento destro, che utilizza un valore padding negativo, aggiungerà spazi alla fine del
valore corrente.
Produzione:
È possibile utilizzare i due punti e la sintassi del formato numerico standard per controllare la
formattazione dei numeri.
https://riptutorial.com/it/home 442
Live Demo su .NET Fiddle
https://riptutorial.com/it/home 443
Capitolo 88: iteratori
Osservazioni
Un iteratore è un metodo, ottiene accessor o operatore che esegue un'iterazione personalizzata
su una matrice o una classe di raccolta utilizzando la parola chiave yield
Examples
Esempio di Iterator numerico semplice
Un caso d'uso comune per gli iteratori consiste nell'eseguire alcune operazioni su una serie di
numeri. L'esempio seguente mostra come ogni elemento all'interno di una matrice di numeri può
essere stampato individualmente sulla console.
Ciò è possibile perché gli array implementano l'interfaccia IEnumerable , consentendo ai client di
ottenere un iteratore per l'array utilizzando il metodo GetEnumerator() . Questo metodo restituisce
un enumeratore , che è un cursore di sola lettura, forward-only su ciascun numero nell'array.
int[] numbers = { 1, 2, 3, 4, 5 };
while (iterator.MoveNext())
{
Console.WriteLine(iterator.Current);
}
Produzione
1
2
3
4
5
È anche possibile ottenere gli stessi risultati usando una dichiarazione foreach :
Iteratori producono gli enumeratori. In C #, gli enumeratori vengono prodotti definendo metodi,
proprietà o indicizzatori che contengono dichiarazioni di yield .
https://riptutorial.com/it/home 444
La maggior parte dei metodi restituirà il controllo al chiamante tramite normali dichiarazioni di
return , che dispone di tutto lo stato locale per tale metodo. Al contrario, i metodi che utilizzano le
dichiarazioni di yield consentono loro di restituire più valori al chiamante su richiesta, preservando
allo stesso tempo lo stato locale nel restituire tali valori. Questi valori restituiti costituiscono una
sequenza. Esistono due tipi di dichiarazioni di yield utilizzate all'interno degli iteratori:
• yield break , che funziona in modo simile a una normale dichiarazione di return - questo
indica la fine della sequenza. Le dichiarazioni di return normali sono illegali all'interno di un
blocco iteratore.
Questo esempio di seguito mostra un metodo iteratore che può essere utilizzato per generare la
sequenza di Fibonacci :
Questo iteratore può quindi essere utilizzato per produrre un enumeratore della sequenza di
Fibonacci che può essere utilizzata da un metodo di chiamata. Il seguente codice mostra come
possono essere enumerati i primi dieci termini all'interno della sequenza di Fibonacci:
void Main()
{
foreach (int term in Fibonacci(10))
{
Console.WriteLine(term);
}
}
Produzione
1
1
2
3
5
8
13
21
34
55
https://riptutorial.com/it/home 445
Leggi iteratori online: https://riptutorial.com/it/csharp/topic/4243/iteratori
https://riptutorial.com/it/home 446
Capitolo 89: La gestione delle eccezioni
Examples
Gestione delle eccezioni di base
try
{
/* code that could throw an exception */
}
catch (Exception ex)
{
/* handle the exception */
}
Si noti che la gestione di tutte le eccezioni con lo stesso codice spesso non è l'approccio migliore.
Questo è comunemente usato quando qualsiasi routine di gestione delle eccezioni interne fallisce,
come ultima risorsa.
try
{
/* code to open a file */
}
catch (System.IO.FileNotFoundException)
{
/* code to handle the file being not found */
}
catch (System.IO.UnauthorizedAccessException)
{
/* code to handle not being allowed access to the file */
}
catch (System.IO.IOException)
{
/* code to handle IOException or it's descendant other than the previous two */
}
catch (System.Exception)
{
/* code to handle other errors */
}
Fai attenzione che le eccezioni siano valutate in ordine e l'ereditarietà sia applicata. Quindi è
necessario iniziare con quelli più specifici e terminare con il loro antenato. In qualsiasi punto, verrà
eseguito un solo blocco catch.
È consentito creare e generare eccezioni nel proprio codice. L'istanziazione di un'eccezione viene
eseguita allo stesso modo di qualsiasi altro oggetto C #.
https://riptutorial.com/it/home 447
Exception ex = new Exception();
try
{
throw new Exception("Error");
}
catch (Exception ex)
{
Console.Write(ex.Message); // Logs 'Error' to the output window
}
Nota: se stai lanciando una nuova eccezione all'interno di un blocco catch, assicurati che
l'eccezione originale sia passata come "eccezione interna", ad es
void DoSomething()
{
int b=1; int c=5;
try
{
var a = 1;
b = a - 1;
c = a / b;
a = a / c;
}
catch (DivideByZeroException dEx) when (b==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by b because it is zero", dEx);
}
catch (DivideByZeroException dEx) when (c==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by c because it is zero", dEx);
}
}
void Main()
{
try
{
DoSomething();
}
catch (Exception ex)
{
// Logs full error information (incl. inner exception)
Console.Write(ex.ToString());
}
}
In questo caso si presume che l'eccezione non possa essere gestita, ma alcune informazioni utili
vengono aggiunte al messaggio (e l'eccezione originale può ancora essere letta tramite
ex.InnerException da un blocco di eccezioni esterno).
https://riptutorial.com/it/home 448
Mostrerà qualcosa come:
Se stai provando questo esempio in LinqPad, noterai che i numeri di riga non sono molto
significativi (non sempre ti aiutano). Tuttavia, il passaggio di un testo di errore utile come suggerito
sopra spesso riduce significativamente il tempo necessario per rintracciare la posizione dell'errore,
che in questo esempio è chiaramente la linea
c = a / b;
in funzione DoSomething() .
Finalmente blocco
try
{
/* code that could throw an exception */
}
catch (Exception)
{
/* handle the exception */
}
finally
{
/* Code that will be executed, regardless if an exception was thrown / caught or not */
}
Il blocco try / catch / finally può essere molto utile durante la lettura da file.
Per esempio:
FileStream f = null;
try
{
f = File.OpenRead("file.txt");
/* process the file here */
}
finally
{
f?.Close(); // f may be null, so use the null conditional operator.
}
Un blocco try deve essere seguito da un catch o da un blocco finally . Tuttavia, poiché non esiste
un blocco catch, l'esecuzione causerà la chiusura. Prima della conclusione, verranno eseguite le
istruzioni all'interno del blocco finally.
https://riptutorial.com/it/home 449
Nella lettura dei file avremmo potuto usare un blocco using come FileStream (ciò che OpenRead
restituisce) implementa IDisposable .
Anche se c'è una dichiarazione di return nel blocco try , il blocco finally verrà eseguito di solito;
ci sono alcuni casi in cui non lo faranno:
Implementare IErrorHandler per i servizi WCF è un ottimo modo per centralizzare la gestione degli
errori e la registrazione. L'implementazione mostrata qui dovrebbe rilevare eventuali eccezioni non
gestite generate a seguito di una chiamata a uno dei servizi WCF. Inoltre, in questo esempio viene
mostrato come restituire un oggetto personalizzato e come restituire JSON piuttosto che l'XML
predefinito.
Implementare IErrorHandler:
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace BehaviorsAndInspectors
{
public class ErrorHandler : IErrorHandler
{
return true;
} // end
// Create the fault message that is returned (note the ref parameter) with
BaseDataResponseContract
fault = Message.CreateMessage(
version,
string.Empty,
new CustomReturnType { ErrorMessage = "An unhandled exception occurred!" },
https://riptutorial.com/it/home 450
new DataContractJsonSerializer(typeof(BaseDataResponseContract), new
List<Type> { typeof(BaseDataResponseContract) }));
if (ex.GetType() == typeof(VariousExceptionTypes))
{
// You might want to catch different types of exceptions here and process
them differently
}
} // end
} // end class
} // end namespace
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace BehaviorsAndInspectors
{
public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}
https://riptutorial.com/it/home 451
{
var errorHandlerInstance = GetInstance();
} // end class
} // end namespace
Config in Web.config:
...
<system.serviceModel>
<services>
<service name="WebServices.MyService">
<endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
</service>
</services>
<extensions>
<behaviorExtensions>
<!-- This extension if for the WCF Error Handling-->
<add name="ErrorHandlerBehavior"
type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<ErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
....
</system.serviceModel>
...
https://msdn.microsoft.com/en-
us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
http://www.brainthud.com/cards/5218/25441/which-four-behavior-interfaces-exist-for-interacting-
with-a-service-or-client-description-what-methods-do-they- attuare e
https://riptutorial.com/it/home 452
Altri esempi:
IErrorHandler che restituisce un corpo di messaggio errato quando il codice di stato HTTP è 401
Non autorizzato
IErrorHandler non sembra gestire i miei errori in WCF ... qualche idea?
Come rendere il gestore degli errori WCF personalizzato restituire la risposta JSON con codice
http non OK?
È consentito implementare eccezioni personalizzate che possono essere generate come qualsiasi
altra eccezione. Questo ha senso quando vuoi rendere le tue eccezioni distinguibili da altri errori
durante il runtime.
In questo esempio creeremo un'eccezione personalizzata per la gestione chiara dei problemi che
l'applicazione potrebbe avere durante l'analisi di un input complesso.
L'eccezione personalizzata diventa molto utile quando si desidera fornire informazioni aggiuntive
al catcher:
https://riptutorial.com/it/home 453
Le classi personalizzate possono implementare le seguenti funzionalità per supportare scenari
aggiuntivi.
ri-lancio
Durante il processo di analisi, l'eccezione originale è ancora interessante. In questo esempio è un
FormatException perché il codice tenta di analizzare un pezzo di stringa, che dovrebbe essere un
numero. In questo caso l'eccezione personalizzata dovrebbe supportare l'inclusione di "
InnerException ":
//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}
serializzazione
In alcuni casi le eccezioni potrebbero dover attraversare i confini di AppDomain. Questo è il caso
se il parser è in esecuzione nel proprio AppDomain per supportare il ricaricamento delle nuove
configurazioni del parser. In Visual Studio, è possibile utilizzare il modello di Exception per
generare codice come questo.
[Serializable]
public class ParserException : Exception
{
// Constructor without arguments allows throwing your exception without
// providing any information, including error message. Should be included
// if your exception is meaningful without any additional details. Should
// set message by calling base constructor (default message is not helpful).
public ParserException()
: base("Parser failure.")
{}
Utilizzo di ParserException
https://riptutorial.com/it/home 454
try
{
Process.StartRun(fileName)
}
catch (ParserException ex)
{
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x)
{
...
}
try
{
int foo = int.Parse(token);
}
catch (FormatException ex)
{
//Assuming you added this constructor
throw new ParserException(
$"Failed to read {token} as number.",
FileName,
LineNumber,
ex);
}
Problemi di sicurezza
Se esporre il motivo dell'eccezione potrebbe compromettere la sicurezza consentendo agli utenti
di vedere il funzionamento interno dell'applicazione, può essere una cattiva idea avvolgere
l'eccezione interna. Questo potrebbe essere applicato se stai creando una libreria di classi che
verrà utilizzata da altri.
Ecco come puoi generare un'eccezione personalizzata senza avvolgere l'eccezione interna:
try
{
// ...
}
catch (SomeStandardException ex)
{
// ...
throw new MyCustomException(someMessage);
}
https://riptutorial.com/it/home 455
Conclusione
Quando si genera un'eccezione personalizzata (con wrapping o con una nuova eccezione
unwrapped), è necessario generare un'eccezione significativa per il chiamante. Ad esempio, un
utente di una libreria di classi potrebbe non sapere molto su come quella libreria faccia il suo
lavoro interno. Le eccezioni generate dalle dipendenze della libreria di classi non sono
significative. Piuttosto, l'utente desidera un'eccezione pertinente al modo in cui la libreria di classi
utilizza tali dipendenze in modo errato.
try
{
// ...
}
catch (IOException ex)
{
// ...
throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details.
If you are not able to resolve the problem, please call 555-555-1234 for technical
assistance.", ex);
}
Eccezione anti-modelli
Ingerire le eccezioni
Si dovrebbe sempre ripetere l'eccezione nel seguente modo:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
Rilanciare un'eccezione come quella di seguito offusca l'eccezione originale e perderà la traccia
dello stack originale. Non si dovrebbe mai farlo! La traccia dello stack prima del fermo e del
rethrow andrà persa.
try
{
...
}
catch (Exception ex)
{
...
throw ex;
https://riptutorial.com/it/home 456
}
try
{
while (AccountManager.HasMoreAccounts())
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
throw new AccountFoundException(account);
}
}
}
catch (AccountFoundException found)
{
Console.Write("Here are your account details: " + found.Account.Details.ToString());
}
cattura (eccezione)
Ci sono quasi no (alcuni dicono nessuno!) Ragioni per catturare il tipo di eccezione generico nel
codice. Dovresti prendere solo i tipi di eccezioni che ti aspetti di accadere, perché altrimenti
nascondi bug nel tuo codice.
try
{
var f = File.Open(myfile);
// do something
https://riptutorial.com/it/home 457
}
catch (Exception x)
{
// Assume file not found
Console.Write("Could not open file");
// but maybe the error was a NullReferenceException because of a bug in the file handling
code?
}
Meglio fare:
try
{
var f = File.Open(myfile);
// do something which should normally not throw exceptions
}
catch (IOException)
{
Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException)
{
Console.Write("Insufficient rights");
}
Anche il seguente è un cattivo esempio, poiché utilizza eccezioni per aggirare un errore di
programmazione. Non è quello per cui sono progettati.
try
{
DoSomething(myString);
}
catch(ArgumentNullException x)
{
// if this happens, we have a programming error and we should check
// why myString was null in the first place.
}
Chi dice che non puoi lanciare più eccezioni con un solo metodo. Se non sei abituato a giocare
con AggregateExceptions potresti essere tentato di creare la tua struttura dati per rappresentare
https://riptutorial.com/it/home 458
molte cose che vanno storte. Ovviamente ci sono altre strutture dati che non sono un'eccezione,
ma sono ideali come i risultati di una convalida. Anche se giochi con AggregateExceptions potresti
essere dal lato ricevente e gestirli sempre senza rendertene conto che possono esserti utili.
È abbastanza plausibile che un metodo venga eseguito e anche se sarà un fallimento nel suo
insieme, vorrai evidenziare più cose che sono andate storte nelle eccezioni generate. Ad esempio,
questo comportamento può essere visto con il modo in cui i metodi paralleli funzionano come
un'attività suddivisa in più thread e qualsiasi numero di essi potrebbe generare eccezioni e questo
deve essere segnalato. Ecco un esempio sciocco di come potresti trarne beneficio:
if (input1 == 1)
{
exceptions.Add(new ArgumentException("I do not like ones"));
}
if (input2 == 2)
{
exceptions.Add(new ArgumentException("I do not like twos"));
}
if (exceptions.Any())
{
throw new AggregateException("Funny stuff happended during execution",
exceptions);
}
}
In questo modo è possibile gestire piccoli blocchi di codice che sono in grado di funzionare senza
interrompere l'intero meccanismo.
try
{
//some code here
https://riptutorial.com/it/home 459
try
{
//some thing which throws an exception. For Eg : divide by 0
}
catch (DivideByZeroException dzEx)
{
//handle here only this exception
//throw from here will be passed on to the parent catch block
}
finally
{
//any thing to do after it is done.
}
//resume from here & proceed as normal;
}
catch(Exception e)
{
//handle here
}
Nota: evitare di ingerire le eccezioni quando si lancia sul blocco catch genitore
Migliori pratiche
Cheatsheet
FARE NON
Controllo del flusso con istruzioni di controllo Controlla il flusso con le eccezioni
https://riptutorial.com/it/home 460
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
Console.WriteLine(myObject.ToString());
}
Poiché lo snippet precedente riguarda solo la logica dell'eccezione, cosa devo fare se myObject
non è nullo a questo punto? Dove dovrei coprire questa parte della logica? Subito dopo
Console.WriteLine(myObject.ToString()); ? Che ne dici dopo il try...catch bloccare il blocco?
// When execution reaches this point, we are sure that myObject is not null
DoSomethingElseWithMyObject();
}
Mr. Best Practices ha ottenuto la stessa logica con meno codice e una logica chiara e
comprensibile.
https://riptutorial.com/it/home 461
eccezioni possono influire in modo significativo sulle prestazioni.
try
{
//Some code that might throw an exception
}
catch(Exception ex)
{
//empty catch block, bad practice
}
Non ingoiare mai le eccezioni. Ignorare le eccezioni salverà quel momento ma creerà un caos per
la manutenibilità in seguito. Quando si registrano le eccezioni, è necessario registrare sempre
l'istanza dell'eccezione in modo che venga registrata la traccia dello stack completa e non solo il
messaggio di eccezione.
try
{
//Some code that might throw an exception
}
catch(NullException ex)
{
LogManager.Log(ex.ToString());
}
try
{
//Try to save the data to the main database.
}
catch(SqlException ex)
{
//Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the
exception bubble up to a level where it can be handled.
https://riptutorial.com/it/home 462
Eccezione non gestita e thread
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(UnhandledException);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);
}
Lanciare un'eccezione
https://riptutorial.com/it/home 463
Il tuo codice può, e spesso dovrebbe, generare un'eccezione quando qualcosa di insolito è
successo.
https://riptutorial.com/it/home 464
Capitolo 90: Lambda Expressions
Osservazioni
chiusure
Le espressioni lambda catturano implicitamente le variabili utilizzate e creano una chiusura . Una
chiusura è una funzione insieme a un contesto statale. Il compilatore genererà una chiusura ogni
volta che un'espressione lambda "racchiude" un valore dal suo contesto circostante.
Questo può essere importante, poiché finché viene mantenuto il riferimento al valore ora in
safeApplyFilterPredicate , ci sarà un riferimento all'oggetto cui si riferisce attualmente il filterer .
Ciò ha un effetto sulla garbage collection e può causare comportamenti imprevisti se l'oggetto al
quale il filterer riferisce attualmente è mutato.
D'altra parte, le chiusure possono essere utilizzate per deliberare l'effetto di incapsulare un
comportamento che implica riferimenti ad altri oggetti.
Per esempio
Examples
Espressioni lambda di base
https://riptutorial.com/it/home 465
Func<int, int> add1 = i => i + 1;
int Add1(int i)
{
return i + 1;
}
...
Console.WriteLine(add1(42)); //43
Console.WriteLine(Add1(42)); //43
Console.WriteLine(add(100, 250)); //350
Console.WriteLine(Add(100, 250)); //350
Ora machineClosure fa riferimento a una funzione da int a int , che dietro le quinte usa l'istanza
IMachine cui fa riferimento la machine per eseguire il calcolo. Anche se la machine riferimento esce
dall'ambito, finché l'oggetto machineClosure viene mantenuto, l'istanza IMachine originale verrà
https://riptutorial.com/it/home 466
mantenuta come parte di una "chiusura", definita automaticamente dal compilatore.
Attenzione: questo può significare che la stessa chiamata di funzione restituisce valori diversi in
momenti diversi (es. In questo esempio se la macchina mantiene una somma dei suoi ingressi). In
molti casi, questo può essere inaspettato e deve essere evitato per qualsiasi codice in uno stile
funzionale: le chiusure accidentali e inaspettate possono essere una fonte di bug.
https://riptutorial.com/it/home 467
Capitolo 91: Le tuple
Examples
Creare tuple
Le tuple sono create usando tipi generici Tuple<T1> - Tuple<T1,T2,T3,T4,T5,T6,T7,T8> . Ciascuno dei
tipi rappresenta una tupla contenente da 1 a 8 elementi. Gli elementi possono essere di diversi
tipi.
È inoltre possibile creare Tuple.Create usando i metodi statici Tuple.Create . In questo caso, i tipi di
elementi vengono dedotti dal compilatore C #.
7.0
Dal momento che C # 7.0, le tuple possono essere facilmente create usando ValueTuple .
(int number, bool flag, MyClass instance) tuple = (123, true, new MyClass());
Per accedere agli elementi tuple utilizzano Item1 - Item8 proprietà. Saranno disponibili solo le
proprietà con un numero di indice inferiore o uguale alla dimensione della tupla (ovvero non è
possibile accedere Item3 proprietà Item3 in Tuple<T1,T2> ).
var tuple = new Tuple<string, int, bool, MyClass>("foo", 123, true, new MyClass());
var item1 = tuple.Item1; // "foo"
var item2 = tuple.Item2; // 123
var item3 = tuple.Item3; // true
var item4 = tuple.Item4; // new My Class()
Ad esempio, una enumerabile i cui elementi sono di tipo Tuple può essere ordinata in base agli
https://riptutorial.com/it/home 468
operatori di confronto definiti su un elemento specificato:
// Output:
// (1, bar)
// (2, foo)
// (3, qux)
Le tuple possono essere utilizzate per restituire più valori da un metodo senza utilizzare parametri.
Nell'esempio seguente, AddMultiply viene utilizzato per restituire due valori (somma, prodotto).
void Write()
{
var result = AddMultiply(25, 28);
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
}
Produzione:
53
700
Ora C # 7.0 offre un modo alternativo per restituire più valori dai metodi che utilizzano le tuple
valore Ulteriori informazioni sulla struttura ValueTuple .
https://riptutorial.com/it/home 469
Capitolo 92: Leggi e capisci Stacktraces
introduzione
Una traccia dello stack è di grande aiuto durante il debug di un programma. Si otterrà una traccia
stack quando il programma genera un'eccezione e talvolta quando il programma termina in modo
anomalo.
Examples
Traccia dello stack per una semplice NullReferenceException in Windows
Form
La traccia dello stack continua così, ma questa parte è sufficiente per i nostri scopi.
Questa è la parte più importante. Indica la riga esatta in cui si è verificata l'eccezione: riga 29 in
Form1.cs.
Quindi, qui inizia la tua ricerca.
La seconda linea è
a System.Windows.Forms.Control.OnClick (EventArgs e)
Questo è il metodo che ha chiamato button1_Click . Così ora sappiamo che button1_Click , dove si
è verificato l'errore, è stato chiamato da System.Windows.Forms.Control.OnClick .
https://riptutorial.com/it/home 470
Possiamo continuare così; la terza linea è
a System.Windows.Forms.Button.OnClick (EventArgs e)
La traccia dello stack è l'elenco di funzioni che è stato chiamato fino a quando il codice non ha
incontrato l'eccezione. E seguendo questo, puoi capire quale percorso di esecuzione ha seguito il
tuo codice fino a quando non si è trovato nei guai!
Si noti che la traccia dello stack include chiamate dal sistema .Net; normalmente non è necessario
seguire tutti i codici Microsofts System.Windows.Forms per scoprire cosa è andato storto, solo il
codice che appartiene alla propria applicazione.
Quindi lo stack consente al computer di sapere dove è stato interrotto prima di chiamare un nuovo
metodo.
Ma serve anche come aiuto per il debug. Come un detective che traccia i passi compiuti da un
criminale quando commette il crimine, un programmatore può usare lo stack per tracciare i passi
compiuti da un programma prima che si schiantasse.
https://riptutorial.com/it/home 471
Capitolo 93: letterali
Sintassi
• bool: vero o falso
• byte: None, letterale intero convertito implicitamente da int
• sbyte: Nessuno, letterale intero convertito implicitamente da int
• char: avvolgere il valore con virgolette singole
• decimale: M o m
• doppio: D, d o un numero reale
• float: F or f
• int: None, predefinito per i valori interi all'interno dell'intervallo di int
• uint: U, u, o valori interi nell'intervallo di uint
• long: L, l, o valori interi nell'intervallo di long
• ulong: UL, ul, Ul, uL, LU, lu, Lu, lU, o valori interi all'interno della gamma di ulong
• short: None, letterale intero convertito implicitamente da int
• ushort: None, letterale intero convertito implicitamente da int
• stringa: avvolgi il valore con virgolette, opzionalmente aggiunto con @
• null : il valore letterale null
Examples
letterali int
int valori letterali int vengono definiti semplicemente utilizzando valori interi all'interno
dell'intervallo di int :
int i = 5;
uint letterali
uint letterali sono definite utilizzando il suffisso U o u , oppure utilizzando un valore integrale
nell'intervallo uint :
uint ui = 5U;
stringhe letterali
I valori letterali stringa possono contenere sequenze di escape. Vedi Sequenze di escape delle
stringhe
https://riptutorial.com/it/home 472
Inoltre, C # supporta letterali stringa letterali (vedi Stringhe di Verbatim ). Questi sono definiti
avvolgendo il valore con virgolette " , e anteponendolo a @ . Le sequenze di escape vengono
ignorate in letterali stringa letterali e sono inclusi tutti i caratteri di spaziatura:
letterali di carbone
char letterali sono definite avvolgendo il valore con apici singoli ' :
char c = 'h';
I caratteri letterali possono contenere sequenze di escape. Vedi Sequenze di escape delle
stringhe
Un carattere letterale deve essere esattamente un carattere (dopo che tutte le sequenze di
escape sono state valutate). I caratteri letterali vuoti non sono validi. Il carattere predefinito
(restituito per default(char) o new char() ) è '\0' , o il carattere NULL (da non confondere con i
riferimenti null letterali e null).
letterali byte
byte tipo di byte non ha suffisso letterale. I valori letterali interi vengono convertiti implicitamente da
int :
byte b = 127;
letterali sbyte
sbyte tipo sbyte non ha suffisso letterale. I valori letterali interi vengono convertiti implicitamente da
int :
sbyte sb = 127;
letterali decimali
decimal valori letterali decimal sono definiti utilizzando il suffisso M o m su un numero reale:
decimal m = 30.5M;
doppi letterali
double valori letterali double sono definiti utilizzando il suffisso D o d oppure utilizzando un numero
reale:
https://riptutorial.com/it/home 473
double d = 30.5D;
letterali galleggianti
float letterali float vengono definiti utilizzando il suffisso F o f o utilizzando un numero reale:
float f = 30.5F;
letterali lunghi
long letterali long sono definiti utilizzando il suffisso L o l , oppure utilizzando valori interi
nell'intervallo di long :
long l = 5L;
molto letterale
ulong ul = 5UL;
breve letterale
short tipo short non ha valore letterale. I valori letterali interi vengono convertiti implicitamente da
int :
short s = 127;
Ushort letterale
tipo di ushort non ha suffisso letterale. I valori letterali interi vengono convertiti implicitamente da
int :
ushort us = 127;
bool letterali
bool b = true;
https://riptutorial.com/it/home 474
Capitolo 94: Lettura e scrittura di file .zip
Sintassi
1. public static ZipArchive OpenRead (string archiveFileName)
Parametri
Parametro Dettagli
Examples
Scrivere in un file zip
System.IO.Compression
System.IO.Compression.FileSystem
L'esempio seguente restituirà i dati byte[] di un file zippato contenente i file forniti, senza bisogno
di accedere al file system.
https://riptutorial.com/it/home 475
{
ZipArchiveEntry orderEntry = archive.CreateEntry(file.Key); //create a file
with this name
using (BinaryWriter writer = new BinaryWriter(orderEntry.Open()))
{
writer.Write(file.Value); //write the binary data
}
}
}
//ZipArchive must be disposed before the MemoryStream has data
return ms.ToArray();
}
}
Questo esempio ottiene un elenco di file dai dati binari dell'archivio zip forniti:
L'esempio seguente mostra come aprire un archivio zip ed estrarre tutti i file
.txt in una cartella
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string zipPath = @"c:\example\start.zip";
string extractPath = @"c:\example\extract";
https://riptutorial.com/it/home 476
{
entry.ExtractToFile(Path.Combine(extractPath, entry.FullName));
}
}
}
}
}
}
https://riptutorial.com/it/home 477
Capitolo 95: LINQ in XML
Examples
Leggi XML usando LINQ in XML
https://riptutorial.com/it/home 478
Console.WriteLine(employee.Element("Name").Value);
}
https://riptutorial.com/it/home 479
Capitolo 96: LINQ parallelo (PLINQ)
Sintassi
• ParallelEnumerable.Aggregate (func)
• ParallelEnumerable.Aggregate (seed, func)
• ParallelEnumerable.Aggregate (seed, updateAccumulatorFunc, combineAccumulatorsFunc,
resultSelector)
• ParallelEnumerable.Aggregate (seedFactory, updateAccumulatorFunc,
combineAccumulatorsFunc, resultSelector)
• ParallelEnumerable.All (predicato)
• ParallelEnumerable.Any ()
• ParallelEnumerable.Any (predicato)
• ParallelEnumerable.AsEnumerable ()
• ParallelEnumerable.AsOrdered ()
• ParallelEnumerable.AsParallel ()
• ParallelEnumerable.AsSequential ()
• ParallelEnumerable.AsUnordered ()
• ParallelEnumerable.Average (selettore)
• ParallelEnumerable.Cast ()
• ParallelEnumerable.Concat (secondo)
• ParallelEnumerable.Contains (valore)
• ParallelEnumerable.Contains (valore, comparatore)
• ParallelEnumerable.Count ()
• ParallelEnumerable.Count (predicato)
• ParallelEnumerable.DefaultIfEmpty ()
• ParallelEnumerable.DefaultIfEmpty (defaultValue)
• ParallelEnumerable.Distinct ()
• ParallelEnumerable.Distinct (di confronto)
• ParallelEnumerable.ElementAt (indice)
• ParallelEnumerable.ElementAtOrDefault (indice)
• ParallelEnumerable.Empty ()
• ParallelEnumerable.Except (secondo)
• ParallelEnumerable.Except (second, comparer)
• ParallelEnumerable.First ()
• ParallelEnumerable.First (predicato)
• ParallelEnumerable.FirstOrDefault ()
• ParallelEnumerable.FirstOrDefault (predicato)
• ParallelEnumerable.ForAll (azione)
• ParallelEnumerable.GroupBy (keySelector)
• ParallelEnumerable.GroupBy (keySelector, comparatore)
• ParallelEnumerable.GroupBy (keySelector, elementSelector)
• ParallelEnumerable.GroupBy (keySelector, elementSelector, comparatore)
• ParallelEnumerable.GroupBy (keySelector, resultSelector)
https://riptutorial.com/it/home 480
• ParallelEnumerable.GroupBy (keySelector, resultSelector, comparatore)
• ParallelEnumerable.GroupBy (keySelector, elementSelector, ruleSelector)
• ParallelEnumerable.GroupBy (keySelector, elementSelector, ruleSelector, comparatore)
• ParallelEnumerable.GroupJoin (inner, outerKeySelector, innerKeySelector, resultSelector)
• ParallelEnumerable.GroupJoin (inner, outerKeySelector, innerKeySelector, resultSelector,
comparatore)
• ParallelEnumerable.Intersect (secondo)
• ParallelEnumerable.Intersect (secondo, comparatore)
• ParallelEnumerable.Join (inner, outerKeySelector, innerKeySelector, resultSelector)
• ParallelEnumerable.Join (inner, outerKeySelector, innerKeySelector, resultSelector,
comparatore)
• ParallelEnumerable.Last ()
• ParallelEnumerable.Last (predicato)
• ParallelEnumerable.LastOrDefault ()
• ParallelEnumerable.LastOrDefault (predicato)
• ParallelEnumerable.LongCount ()
• ParallelEnumerable.LongCount (predicato)
• ParallelEnumerable.Max ()
• ParallelEnumerable.Max (selettore)
• ParallelEnumerable.Min ()
• ParallelEnumerable.Min (selettore)
• ParallelEnumerable.OfType ()
• ParallelEnumerable.OrderBy (keySelector)
• ParallelEnumerable.OrderBy (keySelector, comparatore)
• ParallelEnumerable.OrderByDescending (keySelector)
• ParallelEnumerable.OrderByDescending (keySelector, comparatore)
• ParallelEnumerable.Range (start, count)
• ParallelEnumerable.Repeat (element, count)
• ParallelEnumerable.Reverse ()
• ParallelEnumerable.Select (selettore)
• ParallelEnumerable.SelectMany (selettore)
• ParallelEnumerable.SelectMany (collectionSelector, resultSelector)
• ParallelEnumerable.SequenceEqual (secondo)
• ParallelEnumerable.SequenceEqual (secondo, comparatore)
• ParallelEnumerable.Single ()
• ParallelEnumerable.Single (predicato)
• ParallelEnumerable.SingleOrDefault ()
• ParallelEnumerable.SingleOrDefault (predicato)
• ParallelEnumerable.Skip (conteggio)
• ParallelEnumerable.SkipWhile (predicato)
• ParallelEnumerable.Sum ()
• ParallelEnumerable.Sum (selettore)
• ParallelEnumerable.Take (conteggio)
• ParallelEnumerable.TakeWhile (predicato)
• ParallelEnumerable.ThenBy (keySelector)
• ParallelEnumerable.ThenBy (keySelector, comparatore)
https://riptutorial.com/it/home 481
• ParallelEnumerable.ThenByDescending (keySelector)
• ParallelEnumerable.ThenByDescending (keySelector, comparatore)
• ParallelEnumerable.ToArray ()
• ParallelEnumerable.ToDictionary (keySelector)
• ParallelEnumerable.ToDictionary (keySelector, comparatore)
• ParallelEnumerable.ToDictionary (elementSelector)
• ParallelEnumerable.ToDictionary (elementSelector, comparatore)
• ParallelEnumerable.ToList ()
• ParallelEnumerable.ToLookup (keySelector)
• ParallelEnumerable.ToLookup (keySelector, comparatore)
• ParallelEnumerable.ToLookup (keySelector, elementSelector)
• ParallelEnumerable.ToLookup (keySelector, elementSelector, comparatore)
• ParallelEnumerable.Union (secondo)
• ParallelEnumerable.Union (secondo, comparatore)
• ParallelEnumerable.Where (predicato)
• ParallelEnumerable.WithCancellation (CancellationToken)
• ParallelEnumerable.WithDegreeOfParallelism (degreeOfParallelism)
• ParallelEnumerable.WithExecutionMode (executionMode)
• ParallelEnumerable.WithMergeOptions (mergeOptions)
• ParallelEnumerable.Zip (second, resultSelector)
Examples
Semplice esempio
Questo esempio mostra come PLINQ può essere utilizzato per calcolare i numeri pari tra 1 e
10.000 utilizzando più thread. Si noti che la lista risultante non sarà ordinata!
WithDegreeOfParallelism
AsOrdered
https://riptutorial.com/it/home 482
Questo esempio mostra come PLINQ può essere utilizzato per calcolare i numeri pari tra 1 e
10.000 utilizzando più thread. L'ordine verrà mantenuto nell'elenco risultante, tuttavia tieni
presente che AsOrdered può danneggiare le prestazioni per un numero elevato di elementi,
pertanto l'elaborazione non ordinata viene preferita quando possibile.
AsUnordered
Le sequenze ordinate possono danneggiare le prestazioni quando si ha a che fare con un gran
numero di elementi. Per mitigarlo, è possibile chiamare AsUnordered quando l'ordine della
sequenza non è più necessario.
https://riptutorial.com/it/home 483
Capitolo 97: Linq to Objects
introduzione
LINQ to Objects fa riferimento all'utilizzo di query LINQ con qualsiasi raccolta IEnumerable.
Examples
Come LINQ to Object esegue query
Le query LINQ non vengono eseguite immediatamente. Quando si crea la query, si sta
semplicemente memorizzando la query per l'esecuzione futura. Solo quando si richiede
effettivamente di iterare la query è la query eseguita (ad esempio in un ciclo for, quando si chiama
ToList, Count, Max, Average, First, ecc.)
Questa è considerata un'esecuzione differita . Ciò consente di creare la query in più passaggi,
potenzialmente modificandola in base a istruzioni condizionali e quindi eseguirla in un secondo
momento solo dopo aver richiesto il risultato.
Dato il codice:
L'esempio sopra memorizza solo la query nella variabile di query . Non esegue la query stessa.
foreach(var n in query) {
Console.WriteLine($"Number selected {n}");
}
Alcuni metodi LINQ attivano anche l'esecuzione della query, Count , First , Max , Average .
Restituiscono valori singoli. ToList e ToArray raccolgono i risultati e li trasformano rispettivamente
in una lista o in una matrice.
Tenere presente che è possibile eseguire iterazioni sulla query più volte se si richiamano più
funzioni LINQ sulla stessa query. Questo potrebbe dare risultati diversi ad ogni chiamata. Se vuoi
lavorare con un solo set di dati, assicurati di salvarlo in un elenco o array.
https://riptutorial.com/it/home 484
{
string[] cars = { "VW Golf",
"Opel Astra",
"Audi A4",
"Ford Focus",
"Seat Leon",
"VW Passat",
"VW Polo",
"Mercedes C-Class" };
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
Nell'esempio sopra, una serie di stringhe (auto) viene utilizzata come una raccolta di oggetti da
interrogare usando LINQ. In una query LINQ, la clausola from viene prima di tutto per introdurre
l'origine dati (automobili) e la variabile range (auto). Quando viene eseguita la query, la variabile di
intervallo servirà come riferimento per ciascun elemento successivo nelle automobili. Poiché il
compilatore può inferire il tipo di auto, non è necessario specificarlo esplicitamente
La clausola WHERE viene utilizzata per interrogare l'array di stringhe (macchine) per trovare e
restituire un sottoinsieme di array che soddisfi la clausola WHERE.
https://riptutorial.com/it/home 485
Generazione di una lista ordinata
A volte è utile ordinare i dati restituiti. La clausola orderby causerà l'ordinamento degli elementi in
base al confronto predefinito per il tipo da ordinare.
class Program
{
static void Main(string[] args)
{
https://riptutorial.com/it/home 486
var car7 = new Car("VW Polo", 69867);
var car8 = new Car("Mercedes C-Class", 67549);
Fino ad ora gli esempi non sembrano sorprendenti in quanto si può semplicemente ripetere l'array
per fare praticamente lo stesso. Tuttavia, con i pochi esempi qui sotto puoi vedere come creare
query più complesse con LINQ to Objects e ottenere di più con molto meno codice.
Nell'esempio seguente possiamo selezionare le auto che sono state vendute oltre 60000 unità e
ordinarle sul numero di unità vendute:
https://riptutorial.com/it/home 487
Nell'esempio qui sotto possiamo selezionare le auto che hanno venduto un numero dispari di unità
e ordinarle alfabeticamente sopra il suo nome:
https://riptutorial.com/it/home 488
Capitolo 98: Lock Statement
Sintassi
• lock (obj) {}
Osservazioni
Utilizzando l'istruzione lock è possibile controllare l'accesso di diversi thread al codice all'interno
del blocco di codice. Viene comunemente usato per prevenire condizioni di gara, ad esempio più
thread che leggono e rimuovono oggetti da una collezione. Poiché il blocco delle forze thread in
attesa di altri thread per uscire da un blocco di codice, può causare ritardi che potrebbero essere
risolti con altri metodi di sincronizzazione.
MSDN
La parola chiave lock assicura che un thread non entri in una sezione critica del codice
mentre un altro thread si trova nella sezione critica. Se un altro thread tenta di inserire
un codice bloccato, attenderà, bloccherà, fino a quando l'oggetto non verrà rilasciato.
System.Threading.Monitor.Enter(refObject);
try
{
// code
}
https://riptutorial.com/it/home 489
finally
{
System.Threading.Monitor.Exit(refObject);
}
Examples
Uso semplice
Nel seguente esempio si suppone che ReserveRoom venga chiamato da diversi thread. La
sincronizzazione con il lock è il modo più semplice per prevenire le condizioni di gara qui. Il corpo
del metodo è circondato da un lock che garantisce che due o più thread non possano eseguirlo
contemporaneamente.
Se un thread raggiunge il lock bloccato mentre un altro thread è in esecuzione al suo interno, il
primo attenderà un altro per uscire dal blocco.
Il codice seguente rilascerà il blocco. Non ci saranno problemi L'istruzione di blocco dietro le
quinte funziona come try finally
lock(locker)
{
throw new Exception();
}
https://riptutorial.com/it/home 490
lock (x) ...
lock(locker)
{
return 5;
}
NB istanze di Type non dovrebbero essere utilizzate per questo (nel codice sopra
typeof(ThreadSafe) ) perché le istanze di Type sono condivise su AppDomains e quindi l'estensione
del blocco può includere codice che non dovrebbe (ad esempio se ThreadSafe è caricato in due
AppDomain nello stesso processo quindi il blocco sulla sua istanza Type si bloccherebbe
reciprocamente).
Anti-pattern e trucchi
https://riptutorial.com/it/home 491
Blocco su una variabile allocata allo stack /
locale
Uno degli errori durante l'utilizzo del lock è l'utilizzo di oggetti locali come locker in una funzione.
Poiché queste istanze di oggetti locali saranno diverse per ogni chiamata della funzione, il lock
non funzionerà come previsto.
// Define object that can be used for thread safety in the AddToList method
readonly object classLock = new object();
https://riptutorial.com/it/home 492
//Meanwhile on other tread
public void SomeOtherMethod()
{
var objInString = obj.ToString(); //this does not block
}
public Base()
{
this.padlock = new object();
this.list = new List<string>();
}
public Base()
{
https://riptutorial.com/it/home 493
this.padlock = new object();
this.list = new List<string>();
}
BulemicCounter.Inc:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldfld UserQuery+BulemicCounter.counterLock
https://riptutorial.com/it/home 494
IL_0008: box System.Int32**
IL_000D: call UserQuery+BulemicCounter.IncInSync
IL_0012: nop
IL_0013: ret
Ciò non significa che non sia possibile utilizzare ValueType in scatola per il blocco del monitor:
IL_0001: ldc.i4.1
IL_0002: box System.Int32
IL_0007: stfld UserQuery+BulemicCounter.counterLock
public WordStats()
{
this.padlock = new object();
this.values = new Dictionary<string, object>();
}
Se ci sono più metodi per accedere al dizionario dei values , il codice può diventare molto lungo e,
soprattutto, bloccare tutto il tempo oscura il suo intento . Il blocco è anche molto facile da
dimenticare e la mancanza di un blocco adeguato può causare errori molto difficili da trovare.
https://riptutorial.com/it/home 495
private readonly ConcurrentDictionary<string, object> values;
public WordStats()
{
this.values = new ConcurrentDictionary<string, object>();
}
L'uso di raccolte simultanee migliora anche le prestazioni, perché tutte impiegano tecniche di lock-
free in una certa misura.
https://riptutorial.com/it/home 496
Capitolo 99: looping
Examples
Stili ciclici
Mentre
Il tipo di loop più banale. Unico inconveniente è che non esiste alcun indizio intrinseco per sapere
dove ti trovi nel ciclo.
Fare
Simile a while , ma la condizione viene valutata alla fine del ciclo anziché all'inizio. Ciò si traduce
nell'esecuzione dei loop almeno una volta.
do
{
/// do something
} while(condition) /// loop while the condition satisfies
Per
Un altro stile di ciclo insignificante. Mentre il ciclo di un indice ( i ) viene aumentato e puoi usarlo.
Viene solitamente utilizzato per la gestione di array.
Per ciascuno
Modo modernizzato per il looping di oggetti IEnumarable . Meno male che non devi pensare
all'indice dell'articolo o al numero di articoli dell'elenco.
Metodo Foreach
https://riptutorial.com/it/home 497
Mentre gli altri stili vengono utilizzati per selezionare o aggiornare gli elementi nelle raccolte,
questo stile viene solitamente utilizzato per chiamare immediatamente un metodo per tutti gli
elementi di una raccolta.
// or
list.ForEach(item => DoSomething(item));
// using an array
Array.ForEach(myArray, Console.WriteLine);
E 'importante notare che questo metodo in disponibile solo su List<T> casi e come un metodo
statico su Array - non è parte di Linq.
Proprio come Linq Foreach, eccetto questo fa il lavoro in modo parallelo. Significa che tutti gli
elementi della collezione eseguiranno l'azione data contemporaneamente, contemporaneamente.
/// or
collection.AsParallel().ForAll(item => DoSomething(item));
rompere
A volte la condizione del ciclo dovrebbe essere controllata nel mezzo del ciclo. Il primo è
probabilmente più elegante del secondo:
for (;;)
{
// precondition code that can change the value of should_end_loop expression
if (should_end_loop)
break;
// do something
}
Alternativa:
if (!endLoop)
{
// do something
https://riptutorial.com/it/home 498
}
}
Nota: nei cicli nidificati e / o switch necessario utilizzare più di una semplice break .
Ciclo Foreach
foreach eseguirà iterazioni su qualsiasi oggetto di una classe che implementa IEnumerable (prendi
nota che IEnumerable<T> eredita da esso). Tali oggetti includono alcuni built-in, ma non limitano a:
List<T> , T[] (array di qualsiasi tipo), Dictionary<TKey, TSource> , nonché interfacce come
IQueryable e ICollection , ecc.
sintassi
osservazioni
1. Il tipo ItemType non ha bisogno di corrispondere al tipo preciso degli articoli, deve solo essere
assegnabile dal tipo di elementi
2. Invece di ItemType , in alternativa si può usare var ItemType il tipo di item da
enumerableObject esaminando l'argomento generico dell'implementazione IEnumerable
3. L'istruzione può essere un blocco, una singola istruzione o anche un'istruzione vuota ( ; )
4. Se enumerableObject non sta implementando IEnumerable , il codice non verrà compilato
5. Durante ogni iterazione, l'oggetto corrente viene castato su ItemType (anche se questo non è
specificato ma inferito dal compilatore tramite var ) e se l'elemento non può essere lanciato
verrà lanciata una InvalidCastException .
è equivalente a:
https://riptutorial.com/it/home 499
Console.WriteLine("Hello " + name);
}
}
finally
{
if (enumerator != null)
enumerator.Dispose();
}
Mentre loop
int n = 0;
while (n < 5)
{
Console.WriteLine(n);
n++;
}
Produzione:
0
1
2
3
4
// Call a custom method that takes a count, and returns an IEnumerator for a list
// of strings with the names of theh largest city metro areas.
IEnumerator<string> largestMetroAreas = GetLargestMetroAreas(4);
while (largestMetroAreas.MoveNext())
{
Console.WriteLine(largestMetroAreas.Current);
}
Uscita di esempio:
Tokyo / Yokohama
Metropolitana di New York
San Paolo
Seul / Incheon
Per Loop
A For Loop è ottimo per fare le cose in un certo periodo di tempo. È come un ciclo While, ma
l'incremento è incluso nella condizione.
https://riptutorial.com/it/home 500
{
// Code
}
Inizializzazione: crea una nuova variabile locale che può essere utilizzata solo nel
ciclo.
Condizione: il ciclo viene eseguito solo se la condizione è vera.
Incremento - Come cambia la variabile ogni volta che viene eseguito il ciclo.
Un esempio:
Produzione:
0
1
2
3
4
Puoi anche lasciare spazi nel For Loop, ma devi avere tutti i punti e virgola per farlo funzionare.
Uscita per 3:
3
5
7
9
11
Do - While Loop
È simile a un ciclo while , tranne che verifica la condizione alla fine del corpo del loop. Il ciclo Do-
While esegue il ciclo una volta indipendentemente dal fatto che la condizione sia vera o meno.
// Sum values from the array until we get a total that's greater than 10,
// or until we run out of values.
int sum = 0;
https://riptutorial.com/it/home 501
int i = 0;
do
{
sum += numbers[i];
i++;
} while (sum <= 10 && i < numbers.Length);
System.Console.WriteLine(sum); // 13
Anelli nidificati
Continua
Oltre alla break , c'è anche la parola chiave continue . Invece di interrompere completamente il
ciclo, salterà semplicemente l'iterazione corrente. Potrebbe essere utile se non vuoi che un codice
venga eseguito se è impostato un valore particolare.
Console.WriteLine(i);
}
Risulterà in:
9
10
Nota: Continue è spesso utile nei cicli while o do-while. For-loops, con condizioni di uscita ben
definite, potrebbe non essere di beneficio.
https://riptutorial.com/it/home 502
Capitolo 100: Manipolazione delle stringhe
Examples
Modifica del caso di caratteri all'interno di una stringa
La classe System.String supporta un numero di metodi per la conversione tra caratteri maiuscoli e
minuscoli in una stringa.
Nota: la ragione per utilizzare le versioni invarianti di questi metodi è impedire la produzione di
lettere impreviste specifiche della cultura. Questo è spiegato qui in dettaglio .
Esempio:
Si noti che è possibile scegliere di specificare una cultura specifica durante la conversione in
lettere minuscole e maiuscole utilizzando i metodi String.ToLower (CultureInfo) e String.ToUpper
(CultureInfo) di conseguenza.
Usando System.String.Contains puoi scoprire se una stringa particolare esiste all'interno di una
stringa. Il metodo restituisce un valore booleano, vero se la stringa esiste altrimenti false.
Per trovare la prima posizione dalla fine di una stringa, utilizzare il metodo
System.String.LastIndexOf :
https://riptutorial.com/it/home 503
string s = "Hello World";
int location = s.LastIndexOf("l"); // location = 9
Il metodo System.String.Trim può essere utilizzato per rimuovere tutti i caratteri spazio iniziale e
finale di una stringa:
Inoltre:
• Per rimuovere lo spazio bianco solo dalla fine di una stringa, utilizzare: System.String.TrimEnd
Il metodo System.String.Substring può essere utilizzato per estrarre una parte della stringa.
Utilizzando il metodo System.String.Replace , è possibile sostituire parte di una stringa con un'altra
stringa.
String.Replace può anche essere utilizzato per rimuovere parte di una stringa, specificando una
stringa vuota come valore di sostituzione:
https://riptutorial.com/it/home 504
sottostringhe della stringa originale, divisa in base a un delimitatore specificato:
Produzione:
Uno
Due
Tre
quattro
Il metodo System.String.Join consente di concatenare tutti gli elementi in una matrice di stringhe,
utilizzando un separatore specificato tra ciascun elemento:
Concatenazione di stringhe
https://riptutorial.com/it/home 505
Capitolo 101: metodi
Examples
Dichiarazione di un metodo
Ogni metodo ha una firma univoca che consiste in un accessorio ( public , private , ...), un
modificatore opzionale ( abstract ), un nome e, se necessario, i parametri del metodo. Nota che il
tipo di reso non fa parte della firma. Un prototipo di metodo ha il seguente aspetto:
ReturnTypepuò essere void per nessun ritorno o può essere di qualsiasi tipo da quelli di base,
come int a classi complesse.
un metodo può avere alcuni o nessun parametro di input. per impostare i parametri per un
metodo, devi dichiarare ognuno come le normali dichiarazioni delle variabili (come int a ), e per
più di un parametro devi usare una virgola tra loro (come int a, int b ).
I parametri possono avere valori predefiniti. per questo dovresti impostare un valore per il
parametro (come int a = 0 ). se un parametro ha un valore predefinito, l'impostazione del valore
di input è facoltativa.
Chiamare un metodo
// Single argument
System.Console.WriteLine("Hello World");
// Multiple arguments
string name = "User";
System.Console.WriteLine("Hello, {0}!", name);
https://riptutorial.com/it/home 506
Chiamando un metodo statico e memorizzando il suo valore di ritorno:
int x = 42;
// The instance method called here is Int32.ToString()
string xAsString = x.ToString();
Parametri e argomenti
Un metodo può dichiarare un numero qualsiasi di parametri (in questo esempio, i , s e o sono i
parametri):
I parametri possono essere utilizzati per passare valori in un metodo, in modo che il metodo possa
funzionare con essi. Questo può essere ogni tipo di lavoro come la stampa dei valori o
l'esecuzione di modifiche all'oggetto a cui fa riferimento un parametro o la memorizzazione dei
valori.
Quando chiami il metodo, devi passare un valore reale per ogni parametro. A questo punto, i
valori che effettivamente passano alla chiamata al metodo sono chiamati Arguments:
Tipi di reso
Se il metodo specifica un valore di ritorno, il metodo deve restituire un valore. A tale scopo, con il
https://riptutorial.com/it/home 507
return dichiarazione. Una volta che è stata raggiunta un'istruzione return , restituisce il valore
specificato e qualsiasi codice dopo che non sarà più eseguito (le eccezioni sono finally blocchi,
che saranno comunque eseguiti prima che il metodo ritorni).
Se il tuo metodo non restituisce nulla ( void ), puoi comunque utilizzare l'istruzione return senza un
valore se vuoi tornare immediatamente dal metodo. Alla fine di tale metodo, tuttavia, una
dichiarazione di return non sarebbe necessaria.
return;
return 0;
return x * 2;
return Console.ReadLine();
Lanciare un'eccezione può terminare l'esecuzione del metodo senza restituire un valore. Inoltre, ci
sono blocchi iteratori, in cui i valori di ritorno sono generati usando la parola chiave yield, ma quelli
sono casi speciali che non verranno spiegati a questo punto.
Parametri predefiniti
Quando si chiama un tale metodo e si omette un parametro per il quale viene fornito un valore
predefinito, il compilatore inserisce automaticamente il valore predefinito.
Tenere presente che i parametri con i valori predefiniti devono essere scritti dopo i parametri
senza valori predefiniti.
ATTENZIONE : poiché funziona in questo modo, i valori predefiniti possono essere problematici in
https://riptutorial.com/it/home 508
alcuni casi. Se si modifica il valore predefinito di un parametro del metodo e non si ricompilano
tutti i chiamanti di quel metodo, tali chiamanti continueranno a utilizzare il valore predefinito che
era presente al momento della compilazione, probabilmente causando incoerenze.
Sovraccarico di metodi
Definizione: quando più metodi con lo stesso nome vengono dichiarati con parametri diversi,
viene indicato come overload del metodo. L'overloading del metodo in genere rappresenta
funzioni identiche nel loro scopo ma vengono scritte per accettare tipi di dati diversi come
parametri.
• Numero di argomenti
• Tipo di argomenti
• Tipo di reso **
Considera un metodo denominato Area che eseguirà funzioni di calcolo, che accetta vari
argomenti e restituisce il risultato.
Esempio
Questo metodo accetta un argomento e restituisce una stringa, se chiamiamo il metodo con un
numero intero (diciamo 5 ) l'output sarà "Area of Square is 25" .
Allo stesso modo, se passiamo due valori doppi a questo metodo, l'output sarà il prodotto dei due
valori e sarà di tipo double. Questo può essere usato per la moltiplicazione e per trovare l'Area dei
rettangoli
Questo può essere usato specialmente per trovare l'area del cerchio, che accetta un doppio
valore ( radius ) e restituisce un altro doppio valore come area.
Ognuno di questi metodi può essere chiamato normalmente senza conflitto - il compilatore
esaminerà i parametri di ciascuna chiamata di metodo per determinare quale versione di Area
deve essere utilizzata.
https://riptutorial.com/it/home 509
string squareArea = Area(2);
double rectangleArea = Area(32.0, 17.5);
double circleArea = Area(5.0); // all of these are valid and will compile.
** Nota che il tipo di ritorno da solo non può distinguere tra due metodi. Ad esempio, se avessimo
due definizioni per Area con gli stessi parametri, ad esempio:
Se è necessario che la classe utilizzi gli stessi nomi di metodo che restituiscono valori diversi, è
possibile rimuovere i problemi di ambiguità implementando un'interfaccia e definendone
esplicitamente l'utilizzo.
Metodo anonimo
I metodi anonimi forniscono una tecnica per passare un blocco di codice come parametro
delegato. Sono metodi con un corpo, ma nessun nome.
class Program
{
static void Main(string[] args)
{
// C# 2.0 definition
IntOp add = delegate(int lhs, int rhs)
{
return lhs + rhs;
};
// C# 3.0 definition
IntOp mul = (lhs, rhs) =>
{
return lhs * rhs;
};
https://riptutorial.com/it/home 510
// Calling each method
Console.WriteLine("2 + 3 = " + add(2, 3));
Console.WriteLine("2 * 3 = " + mul(2, 3));
Console.WriteLine("2 - 3 = " + sub(2, 3));
}
}
Diritti di accesso
// static: is callable on a class even when no instance of the class has been created
public static void MyMethod()
//protected internal: access is limited to the current assembly or types derived from the
containing class.
protected internal void MyMethod()
https://riptutorial.com/it/home 511
Capitolo 102: Metodi DateTime
Examples
DateTime.Add (TimeSpan)
DateTime.AddDays (doppio)
DateTime.AddHours (doppio)
DateTime.AddMilliseconds (doppio)
https://riptutorial.com/it/home 512
date2 - date1, date2.Ticks - date1.Ticks);
if (result < 0)
relationship = "is earlier than";
else if (result == 0)
relationship = "is the same time as";
else relationship = "is later than";
// daysInFeb gets 28 because the year 1998 was not a leap year.
int daysInFeb = System.DateTime.DaysInMonth(1998, Feb);
Console.WriteLine(daysInFeb);
DateTime.AddYears (Int32)
Console.WriteLine();
https://riptutorial.com/it/home 513
Console.WriteLine("{0,2} year(s) from now: {1:d}",
ctr, baseDate.AddYears(ctr));
1. La funzione valuta sempre lo stesso valore di risultato dato lo stesso valore di argomento. Il
valore del risultato della funzione non può dipendere da informazioni o stati nascosti che
possono cambiare durante l'esecuzione del programma o tra diverse esecuzioni del
programma, né può dipendere da qualsiasi ingresso esterno dai dispositivi I / O.
2. La valutazione del risultato non causa alcun effetto collaterale semanticamente osservabile o
output, come la mutazione di oggetti mutabili o l'uscita ai dispositivi I / O
Come sviluppatore devi essere consapevole dei metodi puri e ti imbatterai spesso in molte aree.
Uno che ho visto che morde molti sviluppatori junior sta lavorando con i metodi di classe
DateTime. Molti di questi sono puri e se non si è a conoscenza di questi si può avere una
sorpresa. Un esempio:
Dato l'esempio sopra, ci si può aspettare che il risultato stampato su console sia '26 / 12/2016 'ma
in realtà si finisce con la stessa data. Questo perché AddDays è un metodo puro e non influisce
sulla data originale. Per ottenere l'output previsto, è necessario modificare la chiamata AddDays al
seguente:
sample = sample.AddDays(1);
DateTime.Parse (String)
// Converts the string representation of a date and time to its DateTime equivalent
Console.WriteLine(dateTime.ToString());
// Converts the specified string representation of a date and time to its DateTime equivalent
and returns a value that indicates whether the conversion succeeded
https://riptutorial.com/it/home 514
DateTime dateTime;
Console.WriteLine(result);
}
Potresti volerlo usare durante l'analisi di DateTimes da culture diverse (lingue) , l'esempio
seguente analizza la data olandese.
DateTime dateResult;
var dutchDateString = "31 oktober 1999 04:20";
var dutchCulture = CultureInfo.CreateSpecificCulture("nl-NL");
DateTime.TryParse(dutchDateString, dutchCulture, styles, out dateResult);
// output {31/10/1999 04:20:00}
Esempio di analisi:
DateTime.Parse(dutchDateString, dutchCulture)
// output {31/10/1999 04:20:00}
using System;
https://riptutorial.com/it/home 515
{
public static void Main()
{
var date = new DateTime(2016,12,31);
Data odierna
Per ottenere la data corrente si utilizza la proprietà DateTime.Today . Questo restituisce un oggetto
DateTime con la data di oggi. Quando questo viene quindi convertito. .ToString() , viene eseguito di
default nella località del sistema.
Per esempio:
Console.WriteLine(DateTime.Today);
DateTime Formating
//Create datetime
DateTime dt = new DateTime(2016,08,01,18,50,23,230);
https://riptutorial.com/it/home 516
Vi sono seguenti specificatori di formato personalizzato:
• y (anno)
• M (mese)
• d (giorno)
• h (ora 12)
• H (ora 24)
• m (minuto)
• s (secondo)
• f (seconda frazione)
• F (seconda frazione, gli zero finali sono tagliati)
• t (PM o AM)
• z (fuso orario).
var year = String.Format("{0:y yy yyy yyyy}", dt); // "16 16 2016 2016" year
var month = String.Format("{0:M MM MMM MMMM}", dt); // "8 08 Aug August" month
var day = String.Format("{0:d dd ddd dddd}", dt); // "1 01 Mon Monday" day
var hour = String.Format("{0:h hh H HH}", dt); // "6 06 18 18" hour 12/24
var minute = String.Format("{0:m mm}", dt); // "50 50" minute
var secound = String.Format("{0:s ss}", dt); // "23 23" second
var fraction = String.Format("{0:f ff fff ffff}", dt); // "2 23 230 2300" sec.fraction
var fraction2 = String.Format("{0:F FF FFF FFFF}", dt); // "2 23 23 23" without zeroes
var period = String.Format("{0:t tt}", dt); // "P PM" A.M. or P.M.
var zone = String.Format("{0:z zz zzz}", dt); // "+0 +00 +00:00" time zone
È possibile utilizzare anche il separatore della data / (barra) e il separatore del tempo : (due
punti).
Diciamo che abbiamo una stringa DateTime specifica per la cultura 08-07-2016 11:30:12 PM come
MM-dd-yyyy hh:mm:ss tt e vogliamo convertirla in oggetto DateTime equivalente
Converti una stringa di data e ora in un oggetto DateTime equivalente senza uno specifico
formato di cultura
https://riptutorial.com/it/home 517
Diciamo che abbiamo una stringa DateTime in formato dd-MM-yy hh:mm:ss tt e vogliamo convertirla
in oggetto DateTime equivalente, senza alcuna informazione sulla cultura specifica
Converti una stringa di data e ora in oggetto DateTime equivalente senza alcun formato di
cultura specifico con formato diverso
Diciamo che abbiamo una stringa di date, un esempio come '23 -12-2016 'o '12 / 23/2016' e
vogliamo convertirlo in oggetto DateTime equivalente, senza alcuna informazione sulla cultura
specifica
Per esempio
https://riptutorial.com/it/home 518
{
Console.WriteLine("Converted '{0}' to {1} ({2}).", dateString, dateValue, dateValue.Kind);
else
{
Console.WriteLine("'{0}' is not in an acceptable format.", dateString);
}
https://riptutorial.com/it/home 519
dateString = "2008-06-11T16:11:20.0904778Z";
if(DateTime.TryParseExact(dateString, "o", CultureInfo.InvariantCulture, DateTimeStyles.None,
out dateValue))
{
Console.WriteLine("Converted '{0}' to {1} ({2}).", dateString, dateValue, dateValue.Kind);
}
else
{
Console.WriteLine("'{0}' is not in an acceptable format.", dateString);
}
Uscite
https://riptutorial.com/it/home 520
Capitolo 103: Metodi di estensione
Sintassi
• public static ReturnType MyExtensionMethod (target TargetType)
• public static ReturnType MyExtensionMethod (target TargetType, TArg1 arg1, ...)
Parametri
Parametro Dettagli
Osservazioni
I metodi di estensione sono zucchero sintattico che consente di invocare metodi statici su istanze
di oggetti come se fossero membri del tipo stesso.
I metodi di estensione richiedono un oggetto target esplicito. Sarà necessario utilizzare this parola
chiave per accedere al metodo all'interno del tipo esteso stesso.
I metodi di estensione devono essere dichiarati statici e devono vivere in una classe statica.
La scelta dello spazio dei nomi per la classe del metodo di estensione è un compromesso tra
visibilità e rilevabilità.
L' opzione più comunemente citata è quella di avere uno spazio dei nomi personalizzato per i
metodi di estensione. Tuttavia ciò comporterà uno sforzo di comunicazione in modo che gli utenti
del tuo codice sappiano che esistono i metodi di estensione e dove trovarli.
Un'alternativa è scegliere uno spazio dei nomi in modo tale che gli sviluppatori scoprano i metodi
di estensione tramite Intellisense. Quindi, se si desidera estendere la classe Foo , è logico inserire i
metodi di estensione nello stesso spazio dei nomi di Foo .
È importante rendersi conto che nulla impedisce di utilizzare lo spazio dei nomi di "qualcun
altro" : quindi se si desidera estendere IEnumerable , è possibile aggiungere il proprio metodo di
estensione nello spazio System.Linq nomi System.Linq .
Questa non è sempre una buona idea. Ad esempio, in un caso specifico, potresti voler estendere
un tipo comune ( bool IsApproxEqualTo(this double value, double other) per esempio), ma non
avere quel 'inquinante' l'intero System . In questo caso è preferibile scegliere un namespace locale,
https://riptutorial.com/it/home 521
specifico.
Infine, è anche possibile inserire i metodi di estensione in nessuno spazio dei nomi !
Una buona domanda di riferimento: come gestisci gli spazi dei nomi dei tuoi metodi di estensione?
applicabilità
Bisogna fare attenzione quando si creano metodi di estensione per assicurarsi che siano
appropriati per tutti i possibili input e non siano solo rilevanti per situazioni specifiche. Ad esempio,
è possibile estendere classi di sistema come la string , che rende il nuovo codice disponibile per
qualsiasi stringa. Se il codice deve eseguire una logica specifica del dominio su un formato
stringa specifico del dominio, un metodo di estensione non sarebbe appropriato in quanto la sua
presenza confonderebbe i chiamanti che lavorano con altre stringhe nel sistema.
Examples
Metodi di estensione: panoramica
Un metodo di estensione viene creato aggiungendo un metodo statico a una classe statica
distinta dal tipo originale che viene esteso. La classe statica che contiene il metodo di estensione
è spesso creata al solo scopo di contenere i metodi di estensione.
https://riptutorial.com/it/home 522
I metodi di estensione prendono uno speciale primo parametro che designa il tipo originale che
viene esteso. Questo primo parametro è decorato con la parola chiave this (che costituisce un
uso speciale e distinto di this in C # -it dovrebbe essere compreso come differente dall'uso di this
che consente di fare riferimento ai membri dell'istanza dell'oggetto corrente).
Nell'esempio seguente, il tipo originale che è esteso è la string classe. String è stata estesa da un
metodo Shorten() , che fornisce le funzionalità aggiuntive di accorciamento. La classe statica
StringExtensions è stata creata per contenere il metodo di estensione. Il metodo di estensione
Shorten() mostra che si tratta di un'estensione della string tramite il primo parametro
appositamente contrassegnato. Per mostrare che il metodo Shorten() estende la string , il primo
parametro è contrassegnato da this . Pertanto, la firma completa del primo parametro è this
string text , dove string è il tipo originale che viene esteso e il text è il nome del parametro
scelto.
class Program
{
static void Main()
{
// This calls method String.ToUpper()
var myString = "Hello World!".ToUpper();
L'oggetto passato come primo argomento di un metodo di estensione (che è accompagnato dalla
parola chiave this ) è l'istanza in cui viene chiamato il metodo di estensione.
"some string".Shorten(5);
https://riptutorial.com/it/home 523
Si noti che i metodi di estensione sono utilizzabili solo se si trovano nello stesso spazio dei nomi
della loro definizione, se lo spazio dei nomi viene importato in modo esplicito dal codice
utilizzando il metodo di estensione o se la classe di estensione non ha spazio dei nomi. Le linee
guida di .NET framework raccomandano di inserire le classi di estensione nel proprio spazio dei
nomi. Tuttavia, questo può portare a problemi di scoperta.
Ciò non provoca conflitti tra i metodi di estensione e le librerie utilizzate, a meno che gli spazi dei
nomi che potrebbero essere in conflitto siano esplicitamente inseriti. Ad esempio, LINQ Estensioni
:
using System.Linq; // Allows use of extension methods from the System.Linq namespace
class Program
{
static void Main()
{
var ints = new int[] {1, 2, 3, 4};
Dal momento che C # 6.0, è anche possibile inserire una direttiva using static la classe che
contiene i metodi di estensione. Ad esempio, using static System.Linq.Enumerable; . Ciò rende i
metodi di estensione da quella particolare classe disponibile senza portare altri tipi dallo stesso
spazio dei nomi in ambito.
Quando un metodo di classe con la stessa firma è disponibile, il compilatore dà la priorità alla
chiamata del metodo di estensione. Per esempio:
class Test
{
public void Hello()
{
Console.WriteLine("From Test");
}
}
class Program
{
static void Main()
{
https://riptutorial.com/it/home 524
Test t = new Test();
t.Hello(); // Prints "From Test"
}
}
Notare che se ci sono due funzioni di estensione con la stessa firma e una di esse si trova nello
stesso spazio dei nomi, a quella verrà assegnata una priorità. D'altra parte, se si accede a
entrambi using , allora si verificherà un errore di compilazione con il messaggio:
I metodi di estensione possono anche essere usati come normali metodi di classi statiche. Questo
modo di chiamare un metodo di estensione è più dettagliato, ma è necessario in alcuni casi.
Uso:
https://riptutorial.com/it/home 525
Esistono ancora scenari in cui è necessario utilizzare un metodo di estensione come metodo
statico:
• Risolvere il conflitto con un metodo membro. Questo può accadere se una nuova versione di
una libreria introduce un nuovo metodo membro con la stessa firma. In questo caso, il
metodo membro sarà preferito dal compilatore.
• Risolvere i conflitti con un altro metodo di estensione con la stessa firma. Ciò può accadere
se due librerie includono metodi di estensione e spazi dei nomi simili di entrambe le classi
con metodi di estensione utilizzati nello stesso file.
• Passando il metodo di estensione come un gruppo di metodi in un parametro delegato.
• Esegui il tuo legame con Reflection .
• Utilizzo del metodo di estensione nella finestra Immediata in Visual Studio.
Uso statico
Se si using static direttiva using static per portare i membri statici di una classe statica in ambito
globale, i metodi di estensione vengono saltati. Esempio:
Se rimuovi this modificatore dal primo argomento del metodo Shorten , l'ultima riga verrà
compilata.
Controllo nullo
I metodi di estensione sono metodi statici che si comportano come metodi di istanza. Tuttavia, a
differenza di ciò che accade quando si chiama un metodo di istanza su un riferimento null ,
quando un metodo di estensione viene chiamato con un riferimento null , non lancia una
NullReferenceException . Questo può essere abbastanza utile in alcuni scenari.
https://riptutorial.com/it/home 526
}
}
}
I metodi di estensione sono solo uno zucchero sintattico e non sono in realtà membri della classe
che estendono. Ciò significa che non possono interrompere l'incapsulamento: hanno solo accesso
al public (o quando è implementato nei campi, proprietà e metodi dello stesso assembly, internal
).
Proprio come altri metodi, i metodi di estensione possono utilizzare i generici. Per esempio:
https://riptutorial.com/it/home 527
e chiamandolo sarebbe come:
Visualizza la demo
Visualizza la demo
È anche possibile creare metodi di estensione per tipi parzialmente vincolati in tipi multi generici:
Visualizza la demo
Chiamare il codice:
https://riptutorial.com/it/home 528
int number = 5;
var IsDefault = number.IsDefault();
Visualizza la demo
Viene utilizzato il tipo statico (in fase di compilazione) anziché il dinamico (tipo runtime) per
abbinare i parametri.
https://riptutorial.com/it/home 529
Inoltre, il dispatch basato sul tipo statico non consente di chiamare un metodo di estensione su un
oggetto dynamic :
// Prints True
Console.WriteLine(awesomeString.IsThisAwesome());
dynamicObject.StringValue = awesomeString;
// Prints True
Console.WriteLine(StringExtensions.IsThisAwesome(dynamicObject.StringValue));
La ragione per cui [chiamare i metodi di estensione dal codice dinamico] non funziona
è perché nei normali metodi di estensione del codice non dinamico funziona
eseguendo una ricerca completa di tutte le classi note al compilatore per una classe
statica che ha un metodo di estensione che corrisponde . La ricerca va in ordine in
base alla nidificazione dello spazio dei nomi e disponibile using direttive in ogni spazio
dei nomi.
https://riptutorial.com/it/home 530
Ciò significa che per ottenere una chiamata al metodo di estensione dinamica risolta
correttamente, in qualche modo il DLR deve sapere in fase di esecuzione quali sono
stati tutti i nidi di spazio dei nomi e le direttive di using nel codice sorgente . Non
abbiamo un meccanismo a portata di mano per codificare tutte queste informazioni nel
sito di chiamata. Abbiamo preso in considerazione l'idea di inventare un meccanismo
del genere, ma abbiamo deciso che era troppo costoso e ha prodotto un rischio di
pianificazione eccessivo per meritarlo.
fonte
I metodi di estensione possono essere utilizzati per scrivere wrapper fortemente tipizzati per
oggetti simili a dizionari. Ad esempio una cache, HttpContext.Items in cetera ...
Questo approccio elimina la necessità di utilizzare stringhe letterali come chiavi in tutto il
codebase così come la necessità di eseguire il casting sul tipo richiesto durante l'operazione di
lettura. Complessivamente, crea un modo più sicuro e fortemente tipizzato di interagire con tali
oggetti vagamente tipizzati come dizionari.
Quando un metodo di estensione restituisce un valore che ha lo stesso tipo di this argomento,
può essere utilizzato per "concatenare" una o più chiamate di metodo con una firma compatibile.
Ciò può essere utile per i tipi sealed e / o primitivi e consente la creazione di cosiddette API
"fluide" se i nomi dei metodi vengono letti come il linguaggio naturale umano.
void Main()
{
int result = 5.Increment().Decrement().Increment();
// result is now 6
}
https://riptutorial.com/it/home 531
O come questo
void Main()
{
int[] ints = new[] { 1, 2, 3, 4, 5, 6};
int[] a = ints.WhereEven();
//a is { 2, 4, 6 };
int[] b = ints.WhereEven().WhereGreaterThan(2);
//b is { 4, 6 };
}
È molto conveniente usare i metodi di estensione con le interfacce poiché l'implementazione può
essere archiviata al di fuori della classe e tutto ciò che serve per aggiungere alcune funzionalità
alla classe è di decorare la classe con l'interfaccia.
usare come:
https://riptutorial.com/it/home 532
IList Esempio di metodo di estensione: confronto di 2 elenchi
È possibile utilizzare il seguente metodo di estensione per confrontare i contenuti di due istanze
IList <T> dello stesso tipo.
Per impostazione predefinita, gli elementi vengono confrontati in base al loro ordine all'interno
dell'elenco e gli elementi stessi, passando false al parametro isOrdered confronteranno solo gli
elementi stessi indipendentemente dal loro ordine.
Affinché questo metodo funzioni, il tipo generico ( T ) deve sostituire i metodi Equals e GetHashCode .
Uso:
Metodo:
public static bool Compare<T>(this IList<T> list1, IList<T> list2, bool isOrdered = true)
{
if (list1 == null && list2 == null)
return true;
if (list1 == null || list2 == null || list1.Count != list2.Count)
return false;
if (isOrdered)
{
for (int i = 0; i < list2.Count; i++)
{
var l1 = list1[i];
var l2 = list2[i];
if (
(l1 == null && l2 != null) ||
(l1 != null && l2 == null) ||
(!l1.Equals(l2)))
{
return false;
}
}
return true;
}
else
{
List<T> list2Copy = new List<T>(list2);
//Can be done with Dictionary without O(n^2)
for (int i = 0; i < list1.Count; i++)
{
if (!list2Copy.Remove(list1[i]))
return false;
}
return true;
}
}
https://riptutorial.com/it/home 533
Metodi di estensione con enumerazione
Ora puoi convertire rapidamente il tuo valore enum in un tipo diverso. In questo caso un bool.
In alternativa, i metodi di estensione possono essere utilizzati per aggiungere metodi come
proprietà.
https://riptutorial.com/it/home 534
case Element.Carbon: return 12.0107;
case Element.Nitrogen: return 14.0067;
case Element.Oxygen: return 15.9994;
//Etc
}
return double.Nan;
}
}
Quanto segue è un'interfaccia molto semplice con sovraccarichi di comodità forniti come
estensioni.
https://riptutorial.com/it/home 535
class Program
{
static void Main(string[] args)
{
var formatter = new SecondsTimeFormatter();
// Callers get two method overloads!
Console.WriteLine($"4500ms is rougly {formatter.Format(4500)}");
var span = TimeSpan.FromSeconds(5);
Console.WriteLine($"{span} is formatted as {formatter.Format(span)}");
}
}
Considera l'utilizzo di metodi di estensione come funzioni che racchiudono un altro codice, ecco
un ottimo esempio che utilizza sia un metodo statico che un metodo di estensione per racchiudere
il costrutto Try Catch. Crea il tuo codice Bullet Proof ...
using System;
using System.Diagnostics;
namespace Samples
{
/// <summary>
/// Wraps a try catch statement as a static helper which uses
/// Extension methods for the exception
/// </summary>
public static class Bullet
{
/// <summary>
/// Wrapper for Try Catch Statement
/// </summary>
https://riptutorial.com/it/home 536
/// <param name="code">Call back for code</param>
/// <param name="error">Already handled and logged exception</param>
public static void Proof(Action code, Action<Exception> error)
{
try
{
code();
}
catch (Exception iox)
{
//extension method used here
iox.Log("BP2200-ERR-Unexpected Error");
//callback, exception already handled and logged
error(iox);
}
}
/// <summary>
/// Example of a logging method helper, this is the extension method
/// </summary>
/// <param name="error">The Exception to log</param>
/// <param name="messageID">A unique error ID header</param>
public static void Log(this Exception error, string messageID)
{
Trace.WriteLine(messageID);
Trace.WriteLine(error.Message);
Trace.WriteLine(error.StackTrace);
Trace.WriteLine("");
}
}
/// <summary>
/// Shows how to use both the wrapper and extension methods.
/// </summary>
public class UseBulletProofing
{
public UseBulletProofing()
{
var ok = false;
var result = DoSomething();
if (!result.Contains("ERR"))
{
ok = true;
DoSomethingElse();
}
}
/// <summary>
/// How to use Bullet Proofing in your code.
/// </summary>
/// <returns>A string</returns>
public string DoSomething()
{
string result = string.Empty;
//Note that the Bullet.Proof method forces this construct.
Bullet.Proof(() =>
{
//this is the code callback
result = "DST5900-INF-No Exceptions in this code";
}, error =>
{
//error is the already logged and handled exception
//determine the base result
https://riptutorial.com/it/home 537
result = "DTS6200-ERR-An exception happened look at console log";
if (error.Message.Contains("SomeMarker"))
{
//filter the result for Something within the exception message
result = "DST6500-ERR-Some marker was found in the exception";
}
});
return result;
}
/// <summary>
/// Next step in workflow
/// </summary>
public void DoSomethingElse()
{
//Only called if no exception was thrown before
}
}
}
Una funzione utile dei metodi di estensione è che è possibile creare metodi comuni per
un'interfaccia. Normalmente un'interfaccia non può avere implementazioni condivise, ma con i
metodi di estensione che possono.
In questo esempio, il metodo FeetDriven può essere utilizzato su qualsiasi IVehicle . Questa logica
in questo metodo si applicherebbe a tutti gli IVehicle , quindi può essere fatta in questo modo in
modo che non ci debba essere un FeetDriven nella definizione IVehicle che sarebbe implementata
allo stesso modo per tutti i bambini.
Possiamo creare classi di mapper migliori con i metodi di estensione, Supponiamo di avere alcune
classi DTO
https://riptutorial.com/it/home 538
public class AddressDTO
{
public string Name { get; set; }
}
Il bello qui è che tutti i metodi di mappatura hanno un nome comune (ToViewModel) e possiamo
riutilizzarlo in diversi modi
https://riptutorial.com/it/home 539
Utilizzo dei metodi di estensione per creare nuovi tipi di raccolta (ad esempio
DictList)
È possibile creare metodi di estensione per migliorare l'usabilità per le raccolte nidificate come un
Dictionary con un valore di List<T> .
list.Add(value);
}
dictList.Add("example", 5);
dictList.Add("example", 10);
dictList.Add("example", 15);
dictList.Remove("example", 5);
dictList.Remove("example", 10);
https://riptutorial.com/it/home 540
dictList.Remove("example", 15);
Console.WriteLine(dictList.ContainsKey("example")); // False
Visualizza la demo
https://riptutorial.com/it/home 541
Capitolo 104:
Microsoft.Exchange.WebServices
Examples
Recupera le impostazioni Fuori sede specificate dall'utente
Per prima cosa creiamo un oggetto ExchangeManager , dove il costruttore si connetterà ai servizi per
noi. Ha anche un metodo GetOofSettings , che restituirà l'oggetto OofSettings per l'indirizzo email
specificato:
using System;
using System.Web.Configuration;
using Microsoft.Exchange.WebServices.Data;
namespace SetOutOfOffice
{
class ExchangeManager
{
private ExchangeService Service;
public ExchangeManager()
{
var password =
WebConfigurationManager.ConnectionStrings["Password"].ConnectionString;
Connect("exchangeadmin", password);
}
private void Connect(string username, string password)
{
var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.Credentials = new WebCredentials(username, password);
service.AutodiscoverUrl("[email protected]" ,
RedirectionUrlValidationCallback);
Service = service;
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
return
redirectionUrl.Equals("https://mail.domain.com/autodiscover/autodiscover.xml");
}
public OofSettings GetOofSettings(string email)
{
return Service.GetUserOofSettings(email);
}
}
}
https://riptutorial.com/it/home 542
Aggiorna impostazioni utente specifiche fuori sede
using System;
using System.Web.Configuration;
using Microsoft.Exchange.WebServices.Data;
class ExchangeManager
{
private ExchangeService Service;
public ExchangeManager()
{
var password = WebConfigurationManager.ConnectionStrings["Password"].ConnectionString;
Connect("exchangeadmin", password);
}
private void Connect(string username, string password)
{
var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.Credentials = new WebCredentials(username, password);
service.AutodiscoverUrl("[email protected]" ,
RedirectionUrlValidationCallback);
Service = service;
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
return redirectionUrl.Equals("https://mail.domain.com/autodiscover/autodiscover.xml");
}
/// <summary>
/// Updates the given user's Oof settings with the given details
/// </summary>
public void UpdateUserOof(int oofstate, DateTime starttime, DateTime endtime, int
externalaudience, string internalmsg, string externalmsg, string emailaddress)
{
var newSettings = new OofSettings
{
State = (OofState)oofstate,
Duration = new TimeWindow(starttime, endtime),
ExternalAudience = (OofExternalAudience)externalaudience,
InternalReply = internalmsg,
ExternalReply = externalmsg
};
Service.SetUserOofSettings(emailaddress, newSettings);
}
}
var oofState = 1;
var startDate = new DateTime(01,08,2016);
var endDate = new DateTime(15,08,2016);
var externalAudience = 1;
var internalMessage = "I am not in the office!";
var externalMessage = "I am not in the office <strong>and neither are you!</strong>"
https://riptutorial.com/it/home 543
var theUser = "[email protected]";
https://riptutorial.com/it/home 544
Capitolo 105: Modelli di design creativo
Osservazioni
I modelli creazionali mirano a separare un sistema da come i suoi oggetti sono creati, composti e
rappresentati. Aumentano la flessibilità del sistema in termini di cosa, chi, come e quando creare
oggetti. I modelli creazionali incapsulano la conoscenza delle classi utilizzate da un sistema, ma
nascondono i dettagli di come le istanze di queste classi vengono create e messe insieme. I
programmatori hanno capito che la composizione di sistemi con l'ereditarietà rende questi sistemi
troppo rigidi. I modelli creativi sono progettati per rompere questo stretto accoppiamento.
Examples
Singleton Pattern
Il modello Singleton è progettato per limitare la creazione di una classe esattamente a una singola
istanza.
Questo modello viene utilizzato in uno scenario in cui ha senso avere solo uno di qualcosa, ad
esempio:
• una singola classe che orchestra le interazioni di altri oggetti, es. Classe dirigente
• o una classe che rappresenta un'unica risorsa unica, es. Componente di registrazione
Uno dei metodi più comuni per implementare il pattern Singleton è tramite un metodo factory
statico come CreateInstance() o GetInstance() (o una proprietà statica in C #, Instance ), che viene
quindi progettata per restituire sempre la stessa istanza.
Prevenire la creazione di istanze tramite new può essere realizzato rendendo private. i costruttori
della classe private.
class Singleton
{
// Because the _instance member is made private, the only way to get the single
// instance is via the static Instance property below. This can also be similarly
// achieved with a GetInstance() method instead of the property.
private static Singleton _instance = null;
https://riptutorial.com/it/home 545
{
}
// Every call afterwards will return the single instance created above.
return _instance;
}
}
}
Per illustrare ulteriormente questo modello, il codice seguente controlla se viene restituita
un'istanza identica di Singleton quando la proprietà Instance viene chiamata più di una volta.
class Program
{
static void Main(string[] args)
{
Singleton s1 = Singleton.Instance;
Singleton s2 = Singleton.Instance;
// Both Singleton objects above should now reference the same Singleton instance.
if (Object.ReferenceEquals(s1, s2))
{
Console.WriteLine("Singleton is working");
}
else
{
// Otherwise, the Singleton Instance property is returning something
// other than the unique, single instance when called.
Console.WriteLine("Singleton is broken");
}
}
}
Per vedere altri esempi, incluso come rendere questo thread-safe, visitare: Implementazione
Singleton
Visita "Cosa c'è di male in Singletons?" per maggiori informazioni sui problemi che sorgono con il
loro uso.
In C #, hai la possibilità di creare una classe static , che rende tutti i membri statici e la classe non
https://riptutorial.com/it/home 546
può essere istanziata. Detto questo, è comune vedere le classi statiche usate al posto del modello
Singleton.
Per le principali differenze tra i due, visita C # Singleton Pattern Versus Static Class .
Il metodo di fabbrica è uno dei modelli di progettazione creativi. È usato per affrontare il problema
della creazione di oggetti senza specificare il tipo esatto di risultato. Questo documento ti
insegnerà come usare correttamente il metodo DP di fabbrica.
Lascia che ti spieghi l'idea su un semplice esempio. Immagina di lavorare in una fabbrica che
produce tre tipi di dispositivi: Amperometro, Voltmetro e misuratore di resistenza. Stai scrivendo
un programma per un computer centrale che creerà un dispositivo selezionato, ma non conosci la
decisione finale del tuo capo su cosa produrre.
Creiamo un IDevice interfaccia con alcune funzioni comuni che tutti i dispositivi hanno:
Ora possiamo creare classi che rappresentano i nostri dispositivi. Queste classi devono
implementare IDevice interfaccia IDevice :
https://riptutorial.com/it/home 547
r = new Random();
}
public int Measure() { return r.Next(-230, 230); }
public void TurnOff() { Console.WriteLine("VoltMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("VoltMeter turns on..."); }
}
Ora dobbiamo definire il metodo di fabbrica. DeviceFactory classe DeviceFactory con il metodo
statico all'interno:
device = DeviceFactory.CreateDevice(Device.VOLT);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
device = DeviceFactory.CreateDevice(Device.OHM);
device.TurnOn();
https://riptutorial.com/it/home 548
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
}
}
Questo è l'output di esempio che potresti vedere dopo aver eseguito questo codice:
36
33
43
24
102
-61
85
138
36
723.828
368.536
685.412
800.266
578.595
https://riptutorial.com/it/home 549
Modello costruttore
In questo esempio viene illustrato il modello di Builder in cui diversi veicoli vengono assemblati in
modo graduale. Lo Shop utilizza VehicleBuilders per costruire una varietà di veicoli in una serie di
passaggi sequenziali.
using System;
using System.Collections.Generic;
namespace GangOfFour.Builder
{
/// <summary>
/// MainApp startup class for Real-World
/// Builder Design Pattern.
/// </summary>
public class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
VehicleBuilder builder;
/// <summary>
/// The 'Director' class
/// </summary>
class Shop
{
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
https://riptutorial.com/it/home 550
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
vehicleBuilder.BuildDoors();
}
}
/// <summary>
/// The 'Builder' abstract class
/// </summary>
abstract class VehicleBuilder
{
protected Vehicle vehicle;
/// <summary>
/// The 'ConcreteBuilder1' class
/// </summary>
class MotorCycleBuilder : VehicleBuilder
{
public MotorCycleBuilder()
{
vehicle = new Vehicle("MotorCycle");
}
/// <summary>
/// The 'ConcreteBuilder2' class
/// </summary>
https://riptutorial.com/it/home 551
class CarBuilder : VehicleBuilder
{
public CarBuilder()
{
vehicle = new Vehicle("Car");
}
/// <summary>
/// The 'ConcreteBuilder3' class
/// </summary>
class ScooterBuilder : VehicleBuilder
{
public ScooterBuilder()
{
vehicle = new Vehicle("Scooter");
}
/// <summary>
/// The 'Product' class
https://riptutorial.com/it/home 552
/// </summary>
class Vehicle
{
private string _vehicleType;
private Dictionary<string,string> _parts =
new Dictionary<string,string>();
// Constructor
public Vehicle(string vehicleType)
{
this._vehicleType = vehicleType;
}
// Indexer
public string this[string key]
{
get { return _parts[key]; }
set { _parts[key] = value; }
}
Produzione
Modello di prototipo
https://riptutorial.com/it/home 553
Specificare il tipo di oggetti da creare utilizzando un'istanza prototipo e creare nuovi oggetti
copiando questo prototipo.
In questo esempio viene illustrato il pattern Prototype in cui vengono creati nuovi oggetti Color
copiando i colori preesistenti definiti dall'utente dello stesso tipo.
using System;
using System.Collections.Generic;
namespace GangOfFour.Prototype
{
/// <summary>
/// MainApp startup class for Real-World
/// Prototype Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
ColorManager colormanager = new ColorManager();
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
class Color : ColorPrototype
{
private int _red;
private int _green;
private int _blue;
https://riptutorial.com/it/home 554
// Constructor
public Color(int red, int green, int blue)
{
this._red = red;
this._green = green;
this._blue = blue;
}
/// <summary>
/// Prototype manager
/// </summary>
class ColorManager
{
private Dictionary<string, ColorPrototype> _colors =
new Dictionary<string, ColorPrototype>();
// Indexer
public ColorPrototype this[string key]
{
get { return _colors[key]; }
set { _colors.Add(key, value); }
}
}
}
Produzione:
Fornire un'interfaccia per creare famiglie di oggetti correlati o dipendenti senza specificare le loro
classi concrete.
In questo esempio viene dimostrata la creazione di diversi mondi animali per un gioco per
computer che utilizza diverse fabbriche. Sebbene gli animali creati dalle fabbriche del continente
siano diversi, le interazioni tra gli animali rimangono le stesse.
using System;
https://riptutorial.com/it/home 555
namespace GangOfFour.AbstractFactory
{
/// <summary>
/// MainApp startup class for Real-World
/// Abstract Factory Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
// Create and run the African animal world
ContinentFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld(africa);
world.RunFoodChain();
/// <summary>
/// The 'AbstractFactory' abstract class
/// </summary>
abstract class ContinentFactory
{
public abstract Herbivore CreateHerbivore();
public abstract Carnivore CreateCarnivore();
}
/// <summary>
/// The 'ConcreteFactory1' class
/// </summary>
class AfricaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Wildebeest();
}
public override Carnivore CreateCarnivore()
{
return new Lion();
}
}
/// <summary>
/// The 'ConcreteFactory2' class
/// </summary>
class AmericaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Bison();
https://riptutorial.com/it/home 556
}
public override Carnivore CreateCarnivore()
{
return new Wolf();
}
}
/// <summary>
/// The 'AbstractProductA' abstract class
/// </summary>
abstract class Herbivore
{
}
/// <summary>
/// The 'AbstractProductB' abstract class
/// </summary>
abstract class Carnivore
{
public abstract void Eat(Herbivore h);
}
/// <summary>
/// The 'ProductA1' class
/// </summary>
class Wildebeest : Herbivore
{
}
/// <summary>
/// The 'ProductB1' class
/// </summary>
class Lion : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Wildebeest
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
/// <summary>
/// The 'ProductA2' class
/// </summary>
class Bison : Herbivore
{
}
/// <summary>
/// The 'ProductB2' class
/// </summary>
class Wolf : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Bison
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
https://riptutorial.com/it/home 557
/// <summary>
/// The 'Client' class
/// </summary>
class AnimalWorld
{
private Herbivore _herbivore;
private Carnivore _carnivore;
// Constructor
public AnimalWorld(ContinentFactory factory)
{
_carnivore = factory.CreateCarnivore();
_herbivore = factory.CreateHerbivore();
}
Produzione:
https://riptutorial.com/it/home 558
Capitolo 106: Modelli di progettazione
strutturale
introduzione
I modelli di progettazione strutturale sono schemi che descrivono come gli oggetti e le classi
possono essere combinati e formare una struttura di grandi dimensioni e che facilitano la
progettazione identificando un modo semplice per realizzare relazioni tra entità. Ci sono sette
modelli strutturali descritti. Sono i seguenti: Adattatore, Ponte, Composito, Decoratore, Facciata,
Peso mosca e Proxy
Examples
Modello di disegno dell'adattatore
1. ITarget: questa è l'interfaccia che viene utilizzata dal client per ottenere
funzionalità.
2. Adaptee: questa è la funzionalità che il cliente desidera, ma la sua interfaccia
non è compatibile con il client.
3. Cliente: questa è la classe che vuole ottenere alcune funzionalità utilizzando il
codice dell'adaparte.
4. Adapter: questa è la classe che implementerebbe ITarget e chiamerebbe il
codice Adaptee che il client desidera chiamare.
UML
https://riptutorial.com/it/home 559
Primo esempio di codice (esempio teorico) .
/// <summary>
/// Interface: This is the interface which is used by the client to achieve functionality.
/// </summary>
https://riptutorial.com/it/home 560
public interface ITarget
{
List<string> GetEmployeeList();
}
/// <summary>
/// Adaptee: This is the functionality which the client desires but its interface is not
compatible with the client.
/// </summary>
public class CompanyEmplyees
{
public string[][] GetEmployees()
{
string[][] employees = new string[4][];
return employees;
}
}
/// <summary>
/// Client: This is the class which wants to achieve some functionality by using the adaptee’s
code (list of employees).
/// </summary>
public class ThirdPartyBillingSystem
{
/*
* This class is from a thirt party and you do'n have any control over it.
* But it requires a Emplyee list to do its work
*/
}
}
/// <summary>
/// Adapter: This is the class which would implement ITarget and would call the Adaptee code
which the client wants to call.
/// </summary>
public class EmployeeAdapter : CompanyEmplyees, ITarget
https://riptutorial.com/it/home 561
{
public List<string> GetEmployeeList()
{
List<string> employeeList = new List<string>();
string[][] employees = GetEmployees();
foreach (string[] employee in employees)
{
employeeList.Add(employee[0]);
employeeList.Add(",");
employeeList.Add(employee[1]);
employeeList.Add(",");
employeeList.Add(employee[2]);
employeeList.Add("\n");
}
return employeeList;
}
}
///
/// Demo
///
class Programs
{
static void Main(string[] args)
{
ITarget Itarget = new EmployeeAdapter();
ThirdPartyBillingSystem client = new ThirdPartyBillingSystem(Itarget);
client.ShowEmployeeList();
Console.ReadKey();
}
}
Quando usare
• Consentire a un sistema di utilizzare classi di un altro sistema che non è compatibile con
esso.
• Consentire la comunicazione tra sistemi nuovi e già esistenti che sono indipendenti l'uno
dall'altro
• Ado.Net SqlAdapter, OracleAdapter, MySqlAdapter sono il miglior esempio di Adapter
Pattern.
https://riptutorial.com/it/home 562
Capitolo 107: Modificatori di accesso
Osservazioni
Se il modificatore di accesso è omesso,
I modificatori di accesso su setter o getter di proprietà possono limitare l'accesso, non public
string someProperty {get; private set;} : public string someProperty {get; private set;}
Examples
pubblico
La parola chiave public rende una classe (comprese le classi nidificate), proprietà, metodi o campi
disponibili per ogni consumatore:
privato
La parola chiave private contrassegna proprietà, metodi, campi e classi nidificate per l'uso solo
all'interno della classe:
https://riptutorial.com/it/home 563
private class Baz
{
public string Value { get; set; }
}
interno
La parola chiave internal rende una classe (incluse le classi nidificate), proprietà, metodi o campi
disponibili per ogni utente nello stesso assembly:
Questo può essere interrotto per consentire a un assembly di test di accedere al codice
aggiungendo il codice al file AssemblyInfo.cs:
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
protetta
https://riptutorial.com/it/home 564
La parola chiave protected segna il campo, le proprietà dei metodi e le classi nidificate per l'uso
solo all'interno della stessa classe e delle classi derivate:
protetto interno
Assemblea 1
https://riptutorial.com/it/home 565
{
Foo foo = new Foo();
var myPublicProperty = foo.MyPublicProperty;
var myProtectedInternalProperty = foo.MyProtectedInternalProperty;
var myProtectedInternalNestedInstance =
new Foo.MyProtectedInternalNestedClass();
}
}
Assemblea 2
void MyMethod2()
{
Foo foo = new Foo();
var myPublicProperty = foo.MyPublicProperty;
// Compile Error
var myProtectedInternalProperty = foo.MyProtectedInternalProperty;
// Compile Error
var myProtectedInternalNestedInstance =
new Foo.MyProtectedInternalNestedClass();
}
// Compile Error
var myProtectedInternalProperty = baz.MyProtectedInternalProperty;
// Compile Error
var myProtectedInternalNestedInstance =
new Baz.MyProtectedInternalNestedClass();
}
void MyMethod2()
{
Foo foo = new Foo();
var myPublicProperty = foo.MyPublicProperty;
//Compile Error
var myProtectedInternalProperty = foo.MyProtectedInternalProperty;
// Compile Error
var myProtectedInternalNestedInstance =
new Foo.MyProtectedInternalNestedClass();
}
}
https://riptutorial.com/it/home 566
Access Modifiers Diagrams
Ecco tutti i modificatori di accesso nei diagrammi di Venn, da più limitanti a più accessibili:
privato
interno
protetta
protetto interno
https://riptutorial.com/it/home 567
Modificatore d'accesso Diagramma
pubblico
https://riptutorial.com/it/home 568
Capitolo 108: Networking
Sintassi
• TcpClient (host stringa, porta int);
Osservazioni
È possibile ottenere NetworkStream da un TcpClient con client.GetStream() e trasferirlo in uno
StreamReader/StreamWriter per accedere ai propri metodi di lettura e scrittura asincroni.
Examples
Client di comunicazione TCP di base
Questo esempio di codice crea un client TCP, invia "Hello World" sulla connessione socket e
quindi scrive la risposta del server alla console prima di chiudere la connessione.
// Declare Variables
string host = "stackoverflow.com";
int port = 9999;
int timeout = 5000;
Il download di un file da Internet è un'attività molto comune richiesta da quasi tutte le applicazioni
che è probabile creare.
https://riptutorial.com/it/home 569
using (var webClient = new WebClient())
{
webClient.DownloadFile("http://www.server.com/file.txt", "C:\\file.txt");
}
Ciò che questo esempio fa è usare "using" per assicurarti che il tuo web client sia ripulito
correttamente al termine, e semplicemente trasferisce la risorsa denominata dall'URL nel primo
parametro, al file chiamato sul tuo disco rigido locale nel secondo parametro.
Il primo parametro è di tipo " System.Uri ", il secondo parametro è di tipo " System.String "
Puoi anche usare questa funzione come una forma asincrona, in modo che si spenga ed esegua il
download in background, mentre la tua applicazione va avanti con qualcos'altro, usare la chiamata
in questo modo è di grande importanza nelle moderne applicazioni, in quanto aiuta per mantenere
la tua interfaccia utente reattiva.
Quando si utilizzano i metodi Async, è possibile collegare gestori di eventi che consentono di
monitorare lo stato di avanzamento, in modo da poter ad esempio aggiornare una barra di
avanzamento, ad esempio quanto segue:
Un punto importante da ricordare se si usano comunque le versioni Async, e cioè "State molto
attenti a usarli in una 'sintassi' che usa".
La ragione di questo è abbastanza semplice. Una volta chiamato il metodo del download, verrà
restituito immediatamente. Se si dispone di questo in un blocco using, si tornerà quindi uscire da
quel blocco e disporre immediatamente l'oggetto classe e quindi annullare il download in corso.
// Declare Variables
string host = "stackoverflow.com";
int port = 9999;
int timeout = 5000;
https://riptutorial.com/it/home 570
{
// Asynchronsly attempt to connect to server
await client.ConnectAsync(host, port);
Questo esempio di codice crea un client UDP quindi invia "Hello World" attraverso la rete al
destinatario previsto. Un ascoltatore non deve essere attivo, poiché UDP è senza connessione e
trasmetterà il messaggio indipendentemente. Una volta inviato il messaggio, il lavoro dei clienti è
terminato.
Di seguito è riportato un esempio di un listener UDP per integrare il client precedente. Si siederà e
ascolterà costantemente per il traffico su una determinata porta e semplicemente scriverà quei
dati sulla console. Questo esempio contiene un flag di controllo ' done ' che non è impostato
internamente e si affida a qualcosa per impostarlo per consentire la fine del listener e l'uscita.
https://riptutorial.com/it/home 571
while(!done)
{
byte[] receivedData = listener.Receive(ref listenPort);
https://riptutorial.com/it/home 572
Capitolo 109: nome dell'operatore
introduzione
L'operatore nameof consente di ottenere il nome di una variabile , di un tipo o di un membro in
forma stringa senza codificarlo come letterale.
L'operazione viene valutata in fase di compilazione, il che significa che è possibile rinominare un
identificatore di riferimento, utilizzando la funzione di ridenominazione di IDE e la stringa di nome
verrà aggiornata con esso.
Sintassi
• nameof (espressione)
Examples
Utilizzo di base: stampa di un nome di variabile
L'operatore nameof consente di ottenere il nome di una variabile, di un tipo o di un membro in forma
stringa senza codificarlo come letterale. L'operazione viene valutata in fase di compilazione, il che
significa che è possibile rinominare, utilizzando la funzione di ridenominazione di IDE, un
identificatore di riferimento e la stringa di nome si aggiornerà con esso.
Uscirebbe
mystring
perché il nome della variabile è "myString". Il refactoring del nome della variabile cambierebbe la
stringa.
Frammento
https://riptutorial.com/it/home 573
public void DoSomething(int paramValue)
{
Console.WriteLine(nameof(paramValue));
}
...
Uscita console
paramValue
Frammento
_address = value;
OnPropertyChanged(nameof(Address));
}
}
}
...
Uscita console
Indirizzo
https://riptutorial.com/it/home 574
Frammento
...
switch (e.PropertyName)
{
case nameof(bugReport.Title):
Console.WriteLine("{0} changed to {1}", e.PropertyName, bugReport.Title);
break;
case nameof(bugReport.Status):
Console.WriteLine("{0} changed to {1}", e.PropertyName, bugReport.Status);
break;
}
}
...
Uscita console
Frammento
...
https://riptutorial.com/it/home 575
Console.WriteLine(nameof(SomeClass<int>));
Uscita console
TItem
SomeClass
Frammento
Console.WriteLine(nameof(CompanyNamespace.MyNamespace));
Console.WriteLine(nameof(MyClass));
Console.WriteLine(nameof(MyClass.MyNestedClass));
Console.WriteLine(nameof(MyNamespace.MyClass.MyNestedClass.MyStaticProperty));
Uscita console
MyNamespace
La mia classe
MyNestedClass
MyStaticProperty
Preferire
Al di sopra di
L'uso della funzione nameof semplifica il refactoring dei parametri del metodo.
https://riptutorial.com/it/home 576
Link di azione MVC fortemente tipizzati
https://riptutorial.com/it/home 577
Capitolo 110: Nullable types
Sintassi
• Nullable<int> i = 10;
• int? j = 11;
• int? k = null;
• Appuntamento? DateOfBirth = DateTime.Now;
• decimale? Quantità = 1,0 m;
• bool? IsAvailable = true;
• char? Lettera = 'a';
• (genere)? variableName
Osservazioni
I tipi Nullable possono rappresentare tutti i valori di un tipo sottostante e null .
I valori Nullable sono in realtà oggetti System.ValueType , quindi possono essere inseriti in box e
unbox. Inoltre, il valore null di un oggetto nullable non è uguale al valore null di un oggetto di
riferimento, è solo una bandiera.
Quando un oggetto nullable boxing, il valore null viene convertito in riferimento null e il valore non
null viene convertito in un tipo sottostante non nullable.
DateTime? dt = null;
var o = (object)dt;
var result = (o == null); // is true
In forma breve:
Examples
https://riptutorial.com/it/home 578
Inizializzazione di un valore nullo
Nullable<int> i = null;
O:
int? i = null;
O:
var i = (int?)null;
Nullable<int> i = 0;
O:
int? i = 0;
int? i = null;
if (i != null)
{
Console.WriteLine("i is not null");
}
else
{
Console.WriteLine("i is null");
}
if (i.HasValue)
{
Console.WriteLine("i is not null");
}
else
{
Console.WriteLine("i is null");
}
https://riptutorial.com/it/home 579
int? i = 10;
Nel caso in cui sia necessario un valore predefinito, è possibile assegnarne uno utilizzando
l'operatore coalescente null , il metodo GetValueOrDefault o il controllo se HasValue int HasValue
prima dell'assegnazione.
int j = i ?? 0;
int j = i.GetValueOrDefault(0);
int j = i.HasValue ? i.Value : 0;
int j = i.Value;
class Program
{
static void Main()
{
int? nullableExample = null;
int result = nullableExample.GetValueOrDefault();
Console.WriteLine(result); // will output the default value for int - 0
int secondResult = nullableExample.GetValueOrDefault(1);
Console.WriteLine(secondResult) // will output our specified default - 1
int thirdResult = nullableExample ?? 1;
Console.WriteLine(secondResult) // same as the GetValueOrDefault but a bit shorter
}
}
Produzione:
0
1
https://riptutorial.com/it/home 580
public class NullableTypesExample
{
static int? _testValue;
Produzione:
nullo
Qualsiasi tipo nullable è un tipo generico . E qualsiasi tipo nullable è un tipo di valore .
Esistono alcuni trucchi che consentono di utilizzare in modo efficace il risultato del metodo
Nullable.GetUnderlyingType durante la creazione di codice correlato agli scopi reflection / code-
generation:
L'utilizzo:
if(type.IsNullable())
https://riptutorial.com/it/home 581
Console.WriteLine("Type is nullable.");
Type underlyingType;
if(type.IsNullable(out underlyingType))
Console.WriteLine("The underlying type is " + underlyingType.Name + ".");
if(type.IsExactOrNullable<int>())
Console.WriteLine("Type is either exact or nullable Int32.");
if(!type.IsExactOrNullable(t => t.IsEnum))
Console.WriteLine("Type is neither exact nor nullable enum.");
Produzione:
System.Nullable`1[System.Int32]
Type is nullable.
The underlying type is Int32.
Type is either exact or nullable Int32.
Type is neither exact nor nullable enum.
https://riptutorial.com/it/home 582
Capitolo 111: NullReferenceException
Examples
Spiegazione di NullReferenceException
Viene generata una NullReferenceException quando si tenta di accedere a un membro non statico
(proprietà, metodo, campo o evento) di un oggetto di riferimento ma è nullo.
Per eseguire il debug di questa eccezione, è abbastanza semplice: sulla riga in cui viene lanciata
l'eccezione, è sufficiente guardare prima di ogni ' . 'o' [ ', o in rare occasioni' ( '.
myGarage.CarCollection[currentIndex.Value].Color = theCarInTheStreet.Color;
• myGarage è null
• myGarage.CarCollection è null
• currentIndex è null
• myGarage.CarCollection[currentIndex.Value] è null
• theCarInTheStreet è null
In modalità di debug, devi solo posizionare il cursore del mouse su ognuno di questi elementi e
troverai il tuo riferimento null. Quindi, quello che devi fare è capire perché non ha un valore. La
correzione dipende totalmente dall'obiettivo del tuo metodo.
if (myGarage == null)
{
Console.WriteLine("Maybe you should buy a garage first!");
}
if (theCarInTheStreet == null)
{
https://riptutorial.com/it/home 583
throw new ArgumentNullException("theCarInTheStreet");
}
In ogni caso, ricorda che un metodo non dovrebbe mai lanciare una NullReferenceException. Se
lo fa, significa che hai dimenticato di controllare qualcosa.
https://riptutorial.com/it/home 584
Capitolo 112: O (n) Algoritmo per la rotazione
circolare di un array
introduzione
Nel mio percorso di studio della programmazione ci sono stati problemi semplici ma interessanti
da risolvere come esercizi. Uno di questi problemi era ruotare un array (o un'altra raccolta) di un
certo valore. Qui condividerò con voi una semplice formula per farlo.
Examples
Esempio di un metodo generico che ruota un array per un dato turno
Vorrei sottolineare che ruotiamo a sinistra quando il valore di spostamento è negativo e ruotiamo a
destra quando il valore è positivo.
array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
shiftCount = -1;
Rotate(ref array, shiftCount);
Console.WriteLine(string.Join(", ", array));
// Output: [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
shiftCount = -35;
Rotate(ref array, shiftCount);
Console.WriteLine(string.Join(", ", array));
// Output: [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
}
https://riptutorial.com/it/home 585
array = backupArray;
}
La cosa importante in questo codice è la formula con cui troviamo il nuovo valore di indice dopo la
rotazione.
(shiftCount% array.Length) -> normalizziamo il valore di spostamento in modo che sia nella
lunghezza dell'array (poiché in un array con lunghezza 10, lo spostamento 1 o 11 è la stessa
cosa, lo stesso vale per -1 e -11) .
array.Length + (shiftCount% array.Length) -> questo viene fatto a causa delle rotazioni a
sinistra per assicurarsi che non entriamo in un indice negativo, ma ruotarlo fino alla fine dell'array.
Senza di esso per una matrice di lunghezza 10 per l'indice 0 e una rotazione -1 dovremmo inserire
un numero negativo (-1) e non ottenere il valore dell'indice di rotazione reale, che è 9. (10 + (-1%
10) = 9)
index + array.Length + (shiftCount% array.Length) -> Non c'è molto da dire qui quando
applichiamo la rotazione all'indice per ottenere il nuovo indice. (0 + 10 + (-1% 10) = 9)
https://riptutorial.com/it/home 586
Capitolo 113: ObservableCollection
Examples
Inizializza ObservableCollection
ObservableCollection è una raccolta di tipo T come List<T> che significa che contiene oggetti di tipo
T
using System.Collections.ObjectModel
È possibile creare un'istanza vuota di una raccolta per esempio di tipo string
https://riptutorial.com/it/home 587
Capitolo 114: Operatore di uguaglianza
Examples
Tipi di uguaglianza in c # e operatore di uguaglianza
Per i tipi di valore predefiniti, l'operatore di uguaglianza (==) restituisce true se i valori dei suoi
operandi sono uguali, false altrimenti. Per i tipi di riferimento diversi da string, == restituisce true
se i suoi due operandi si riferiscono allo stesso oggetto. Per il tipo di stringa, == confronta i valori
delle stringhe.
https://riptutorial.com/it/home 588
Capitolo 115: Operatore Null Coalescing
Sintassi
• var result = possibleNullObject ?? valore predefinito;
Parametri
Parametro Dettagli
Osservazioni
Lo stesso operatore a coalescenza nulla è costituito da due caratteri consecutivi di punti
interrogativi: ??
L'operando di sinistra (oggetto in fase di test) deve essere un tipo di valore o un tipo di riferimento
nullable o si verificherà un errore di compilazione.
Il ?? l'operatore lavora sia per i tipi di riferimento che per i tipi di valore.
Examples
Utilizzo di base
L'utilizzo null-coalescing operator (??) consente di specificare un valore predefinito per un tipo
nullable se l'operando di sinistra è null .
https://riptutorial.com/it/home 589
string testString = null;
if (testString == null)
{
Console.WriteLine("The specified string is - not provided");
}
else
{
Console.WriteLine("The specified string is - " + testString);
}
L'operando di sinistra deve essere annullabile, mentre l'operando di destra può essere o meno. Il
risultato verrà digitato di conseguenza.
Non annullabile
int? a = null;
int b = 3;
var output = a ?? b;
var type = output.GetType();
Produzione:
Tipo: System.Int32
valore: 3
Visualizza la demo
nullable
int? a = null;
int? b = null;
var output = a ?? b;
Coalescenza multipla
int? a = null;
int? b = null;
https://riptutorial.com/it/home 590
int c = 3;
var output = a ?? b ?? c;
Produzione:
Tipo: System.Int32
valore: 3
Visualizza la demo
L'operatore null coalescing può essere utilizzato in tandem con l' operatore di propagazione null
per fornire un accesso più sicuro alle proprietà degli oggetti.
object o = null;
var output = o?.ToString() ?? "Default Value";
Produzione:
Tipo: System.String
valore: valore predefinito
Visualizza la demo
L'operatore null coalescente semplifica l'assicurare che un metodo che può restituire null ricada
su un valore predefinito.
if (name == null)
name = "Unknown!";
Uno scenario di utilizzo comune a cui questa funzione è davvero utile è quando si cerca un
oggetto in una raccolta e occorre crearne uno nuovo se non esiste già.
https://riptutorial.com/it/home 591
IEnumerable<MyClass> myList = GetMyList();
var item = myList.SingleOrDefault(x => x.Id == 2) ?? new MyClass { Id = 2 };
La prima volta che si accede alla proprietà .FooBars la variabile _fooBars verrà valutata come null ,
passando quindi all'istruzione di assegnazione assegna e valuterà il valore risultante.
Filo di sicurezza
Questo non è un modo sicuro per implementare le proprietà lazy. Per la pigrizia sicura dei
thread, utilizzare la classe Lazy<T> integrata in .NET Framework.
Gli accessi successivi alla proprietà produrranno il valore memorizzato nella variabile _fooBars .
https://riptutorial.com/it/home 592
Capitolo 116: operatori
introduzione
In C #, un operatore è un elemento di programma che viene applicato a uno o più operandi in
un'espressione o istruzione. Gli operatori che accettano un operando, come l'operatore di
incremento (++) o nuovo, sono indicati come operatori unari. Gli operatori che accettano due
operandi, come gli operatori aritmetici (+, -, *, /), sono indicati come operatori binari. Un operatore,
l'operatore condizionale (? :), prende tre operandi ed è l'unico operatore ternario in C #.
Sintassi
• operatore statico pubblico OperandType operatoreSymbol (OperandType operando1)
• operatore statico pubblico OperandType operatoreSymbol (OperandType operand1,
OperandType2 operando2)
Parametri
Parametro Dettagli
Osservazioni
Tutti gli operatori sono definiti come static methods e non sono virtual e non vengono ereditati.
Precedenza dell'operatore
Tutti gli operatori hanno una "precedenza" particolare a seconda del gruppo in cui ricade
l'operatore (gli operatori dello stesso gruppo hanno la stessa priorità). Significa che alcuni
operatori saranno applicati prima degli altri. Quello che segue è un elenco di gruppi (contenenti i
rispettivi operatori) ordinati per precedenza (prima i più alti):
• Operatori primari
https://riptutorial.com/it/home 593
○ ab - Accesso membri.
○ a?.b - Accesso ai membri condizionali Null.
○ -> - Dereferencing del puntatore combinato con l'accesso dei membri.
○ f(x) - Richiamo funzione.
○ a[x] - Indicizzatore.
○ a?[x] - Indicatore condizionale nullo.
○ x++ - Incremento postfisso.
○ x-- - x-- Postfix.
○ new - Digitare l'istanza.
○ default(T) - Restituisce il valore inizializzato predefinito di tipo T
○ typeof - Restituisce l'oggetto Type dell'operando.
○ checked : abilita il controllo di overflow numerico.
○ unchecked : disattiva il controllo di overflow numerico.
○ delegate - Dichiara e restituisce un'istanza delegata.
○ sizeof - Restituisce la dimensione in byte dell'operando di tipo.
• Operatori unari
○ +x - Restituisce x .
○ -x - Negazione numerica.
○ !x - Negazione logica.
○ ~x - Complemento bit per bit / dichiara i distruttori.
○ ++x - Incremento del prefisso.
○ --x - --x prefisso.
○ (T)x - Tipologia casting.
○ await - Aspetta un Task .
○ &x - Restituisce l'indirizzo (puntatore) di x .
○ *x - Dereferenziamento puntatore.
• Operatori moltiplicativi
○ x * y - Moltiplicazione.
○ x / y - Divisione.
○ x % y - Modulo.
• Operatori additivi
○ x + y - Aggiunta.
○ x – y - sottrazione.
https://riptutorial.com/it/home 594
○ x <= y - Minore o uguale a.
○ x >= y - Maggiore o uguale a.
○ is - Digitare la compatibilità.
○ as - Conversione di tipo.
• Operatori di uguaglianza
○ x == y - Uguaglianza.
○ x != y - Non uguale.
• Logico E Operatore
• Logico O Operatore
• Condizionale E Operatore
• Operatore OR condizionale
• Operatore condizionale
Contenuto relativo
• Operatore Null-Conditional
• nome dell'operatore
Examples
Operatori sovraccarichi
https://riptutorial.com/it/home 595
C # consente ai tipi definiti dall'utente di sovraccaricare gli operatori definendo funzioni membro
statiche utilizzando la parola chiave operator .
L'esempio seguente illustra un'implementazione dell'operatore + .
E vogliamo aggiungere l'opzione per usare l'operatore + per questa classe. vale a dire:
Dovremo sovraccaricare l'operatore + per la classe. Questo viene fatto usando una funzione
statica e la parola chiave operator :
Operatori come + , - , * , / possono essere sovraccaricati. Ciò include anche operatori che non
restituiscono lo stesso tipo (ad esempio, == e != Possono essere sovraccaricati, nonostante il
ritorno di booleani) Viene applicata anche la regola seguente relativa alle coppie.
Gli operatori di confronto devono essere sovraccaricati a coppie (ad esempio, se < è sovraccarico,
> deve essere sovraccaricato).
Un elenco completo degli operatori sovraccaricabili (così come degli operatori non sovraccaricabili
e delle restrizioni imposte ad alcuni operatori sovraccaricabili) può essere visto su MSDN -
Operatori sovraccaricabili (C # Programming Guide) .
7.0
https://riptutorial.com/it/home 596
}
Operatori relazionali
È uguale a
A differenza di Java, l'operatore di confronto delle uguaglianze funziona in modo nativo con le
stringhe.
L'operatore di confronto di uguaglianza funzionerà con operandi di tipi diversi se esiste un cast
implicito da uno all'altro. Se non esiste alcun cast implicito adatto, è possibile chiamare un cast
esplicito o utilizzare un metodo per convertire in un tipo compatibile.
1 == 1.0 // Returns true because there is an implicit cast from int to double.
new Object() == 1.0 // Will not compile.
MyStruct.AsInt() == 1 // Calls AsInt() on MyStruct and compares the resulting int with 1.
https://riptutorial.com/it/home 597
var x = new Object();
var y = new Object();
x == y // Returns false, the operands (objects in this case) have different references.
x == x // Returns true, both operands have the same reference.
Per i tipi di valore, l'operatore restituisce true se entrambi gli operandi hanno valore uguale.
Per i tipi di riferimento, l'operatore restituisce true se entrambi gli operandi sono uguali in
riferimento (non valore). Un'eccezione è che gli oggetti stringa saranno confrontati con
l'uguaglianza dei valori.
Non uguale
Questo operatore restituisce in modo efficace il risultato opposto a quello dell'operatore di uguale (
== )
Più grande di
var x = 10;
var y = 15;
x > y //Returns false.
y > x //Returns true.
Meno di
var x = 12;
var y = 22;
https://riptutorial.com/it/home 598
x < y //Returns true.
y < x //Returns false.
Maggiore di uguale a
Meno di uguale a
Operatori di cortocircuito
Per definizione, gli operatori booleani di cortocircuito valuteranno solo il secondo operando se il
primo operando non è in grado di determinare il risultato complessivo dell'espressione.
Significa che, se si utilizza && operator come firstCondition e& secondCondition , verrà valutata
secondCondition solo quando firstCondition è true e ofcource il risultato complessivo sarà true
solo se entrambi di firstOperand e secondOperand vengono valutati su true. Questo è utile in molti
scenari, ad esempio immagina di voler controllare mentre il tuo elenco ha più di tre elementi ma
devi anche controllare se l'elenco è stato inizializzato per non essere eseguito in
NullReferenceException . Puoi ottenerlo come di seguito:
AND logico
var x = true;
var y = false;
OR logico
https://riptutorial.com/it/home 599
var x = true;
var y = false;
Esempio di utilizzo
taglia di
sizeof(bool) // Returns 1.
sizeof(byte) // Returns 1.
sizeof(sbyte) // Returns 1.
sizeof(char) // Returns 2.
sizeof(short) // Returns 2.
sizeof(ushort) // Returns 2.
sizeof(int) // Returns 4.
sizeof(uint) // Returns 4.
sizeof(float) // Returns 4.
sizeof(long) // Returns 8.
sizeof(ulong) // Returns 8.
sizeof(double) // Returns 8.
sizeof(decimal) // Returns 16.
In un contesto non sicuro, sizeof può essere utilizzato per restituire la dimensione di altri tipi e
strutture primitive.
https://riptutorial.com/it/home 600
Sovraccaricare solo gli operatori di uguaglianza non è sufficiente. In diverse circostanze, è
possibile chiamare tutti i seguenti:
1. object.Equals e object.GetHashCode
2. IEquatable<T>.Equals (facoltativo, consente di evitare la boxe)
3. operator == e operator != (facoltativo, consente di utilizzare gli operatori)
Quando si Equals override di Equals , anche GetHashCode deve essere sostituito. Quando si
implementa Equals , ci sono molti casi speciali: confronto con oggetti di un tipo diverso, confronto
con il sé ecc.
Quando NON viene sovrascritto il metodo Equals e l'operatore == comportano diversamente per le
classi e le strutture. Per le classi vengono confrontati solo i riferimenti e per i valori delle strutture
le proprietà vengono confrontate tramite la riflessione, cosa può influire negativamente sulle
prestazioni. == non può essere usato per confrontare le strutture a meno che non sia sovrascritto.
https://riptutorial.com/it/home 601
public static bool operator !=(Student left, Student right)
{
return !Equals(left, right);
}
}
Questo operatore restituisce true quando uno, ma solo uno, dei bool forniti è vero.
https://riptutorial.com/it/home 602
true ^ false // Returns true
false ^ true // Returns true
false ^ false // Returns false
true ^ true // Returns false
Operatori Bit-Shifting
Destra-Shift
Il metodo non può accettare altri argomenti, né può essere un metodo di istanza. Può, tuttavia,
accedere a qualsiasi membro privato di tipo in cui è definito.
https://riptutorial.com/it/home 603
Consentire la seguente sintassi del cast:
Gli operatori del cast possono lavorare in entrambe le direzioni, andando dal tuo tipo e andando al
tuo tipo:
Infine, la parola chiave as , che può essere coinvolta nel cast all'interno di una gerarchia di tipi,
non è valida in questa situazione. Anche dopo aver definito un cast explicit o implicit , non puoi
fare:
C # ha diversi operatori che possono essere combinati con un segno = per valutare il risultato
dell'operatore e quindi assegnare il risultato alla variabile originale.
Esempio:
x += y
equivale a
x = x + y
Operatori di assegnazione:
• +=
• -=
• *=
• /=
• %=
• &=
https://riptutorial.com/it/home 604
• |=
• ^=
• <<=
• >>=
? : Operatore ternario
Sintassi:
Esempio:
L'operatore ternario ha una associazione destra che consente di utilizzare espressioni ternarie
composte. Questo viene fatto aggiungendo ulteriori equazioni ternarie nella posizione vera o falsa
di un'equazione ternaria genitore. Bisogna fare attenzione per garantire la leggibilità, ma questa
può essere una utile stenografia in alcune circostanze.
In questo esempio, un'operazione ternaria composta valuta una funzione di clamp e restituisce il
valore corrente se è compreso nell'intervallo, il valore min se è inferiore all'intervallo o il valore max
se è superiore all'intervallo.
// This is evaluated from left to right and can be more easily seen with parenthesis:
a ? (b ? x : y) : z
Quando si scrivono dichiarazioni ternarie composte, è comune utilizzare parentesi o rientranza per
migliorare la leggibilità.
condition ? 3 : "Not three"; // Doesn't compile because `int` and `string` lack an implicit
https://riptutorial.com/it/home 605
conversion.
condition ? 3.ToString() : "Not three"; // OK because both possible outputs are strings.
condition ? 3 : 3.5; // OK because there is an implicit conversion from `int` to `double`. The
ternary operator will return a `double`.
condition ? 3.5 : 3; // OK because there is an implicit conversion from `int` to `double`. The
ternary operator will return a `double`.
condition ? new SportsCar() : new Car(); // OK because there is an implicit conversion from
`SportsCar` to `Car`. The ternary operator will return a reference of type `Car`.
condition ? new Car() : new SportsCar(); // OK because there is an implicit conversion from
`SportsCar` to `Car`. The ternary operator will return a reference of type `Car`.
condition ? new SportsCar() : new SUV(); // Doesn't compile because there is no implicit
conversion from `SportsCar` to SUV or `SUV` to `SportsCar`. The compiler is not smart enough
to realize that both of them have an implicit conversion to `Car`.
condition ? new SportsCar() as Car : new SUV() as Car; // OK because both expressions evaluate
to a reference of type `Car`. The ternary operator will return a reference of type `Car`.
tipo di
Per ottenere il tipo di runtime, utilizzare il metodo GetType per ottenere System.Type dell'istanza
corrente.
L'operatore typeof accetta un nome di tipo come parametro, che viene specificato al momento
della compilazione.
https://riptutorial.com/it/home 606
Assert.IsTrue(animal.GetType() == typeof(Dog)); // pass, animal is typeof(Dog)
Assert.IsTrue(animal is Animal); // pass, animal implements Animal
Operatore predefinito
default(int) // 0
default(DateTime) // 0001-01-01 12:00:00 AM
default(char) // '\0' This is the "null character", not a zero or a line break.
default(Guid) // 00000000-0000-0000-0000-000000000000
default(MyStruct) // new MyStruct()
// Note: default of an enum is 0, and not the first *key* in that enum
// so it could potentially fail the Enum.IsDefined test
default(MyEnum) // (MyEnum)0
default(object) // null
default(string) // null
default(MyClass) // null
default(IDisposable) // null
default(dynamic) // null
nome dell'operatore
Restituisce una stringa che rappresenta il nome non qualificato di una variable , type o member .
L'operatore nameof stato introdotto in C # 6.0. Viene valutato in fase di compilazione e il valore
stringa restituito viene inserito inline dal compilatore, quindi può essere utilizzato nella maggior
parte dei casi in cui è possibile utilizzare la stringa costante (ad esempio, le etichette case in
un'istruzione switch , attributi, ecc. .). Può essere utile in casi come le eccezioni di sollevamento e
registrazione, gli attributi, i link di azione MVC, ecc ...
6.0
https://riptutorial.com/it/home 607
Introdotto in C # 6.0 , il Null Conditional Operator ?. immediatamente restituire null se
l'espressione sul suo lato sinistro restituisce null , invece di lanciare un NullReferenceException .
Se il suo lato sinistro valuta un valore non null , viene trattato come un normale . operatore. Si
noti che poiché potrebbe restituire null , il suo tipo restituito è sempre un tipo nullable. Ciò
significa che per una struttura o un tipo primitivo, è racchiuso in un Nullable<T> .
Questo è utile quando si attivano gli eventi. Normalmente dovresti racchiudere la chiamata
dell'evento in un'istruzione if che verifica il null e innalza l'evento in seguito, che introduce la
possibilità di una race condition. Utilizzando l'operatore condizionale Null, questo può essere
risolto nel seguente modo:
var x = 42;
x++;
Console.WriteLine(x); // 43
var x = 42
x--;
Console.WriteLine(x); // 41
++x è chiamato incremento prefisso incrementa il valore di x e quindi restituisce x mentre x++
restituisce il valore di x e quindi incrementi
var x = 42;
Console.WriteLine(++x); // 43
System.out.println(x); // 43
mentre
var x = 42;
Console.WriteLine(x++); // 42
System.out.println(x); // 43
https://riptutorial.com/it/home 608
=> Operatore Lambda
3.0
Viene utilizzato per dichiarare espressioni lambda e inoltre è ampiamente utilizzato con query
LINQ :
Se utilizzato nelle estensioni o nelle query LINQ, il tipo di oggetti può essere saltato in genere
poiché viene dedotto dal compilatore:
int shortestWordLength = words.Min(w => w.Length); //also compiles with the same result
I parametri dell'espressione lambda sono specificati prima => operatore e l'espressione / istruzione
/ blocco effettivo da eseguire è a destra dell'operatore:
// expression
(int x, string s) => s.Length > x
// expression
(int x, int y) => x + y
// statement
(string x) => Console.WriteLine(x)
// block
(string x) => {
x += " says Hello!";
Console.WriteLine(x);
}
Questo operatore può essere utilizzato per definire facilmente i delegati, senza scrivere un metodo
esplicito:
myDelegate("Hello");
invece di
https://riptutorial.com/it/home 609
void MyMethod(string s)
{
Console.WriteLine(s + " World");
}
myDelegate("Hello");
L'operatore Null-Coalescing ?? restituirà il lato sinistro quando non è nullo. Se è nullo, restituirà il
lato destro.
https://riptutorial.com/it/home 610
Capitolo 117: Operatori non condizionali
Sintassi
• ? X .Y; // null se X è nullo XY
• ?? X .Y .Z; // null se X è null o Y è null else XYZ
• ? X [index]; // null se X è null else X [index]
• ? X .ValueMethod (); // null se X è null else il risultato di X.ValueMethod ();
• ? X .VoidMethod (); // non fare nulla se X è null altrimenti chiama X.VoidMethod ();
Osservazioni
Si noti che quando si utilizza l'operatore null coalescing su un tipo di valore T si ottiene un back
Nullable<T> null Nullable<T> .
Examples
Operatore Null-Conditional
Il ?. l'operatore è zucchero sintattico per evitare verosimili controlli null. È anche noto come
operatore di navigazione sicura .
Se un oggetto è potenzialmente nullo (come una funzione che restituisce un tipo di riferimento),
l'oggetto deve prima essere verificato per null per impedire una possibile NullReferenceException .
Senza l'operatore condizionale nullo, questo apparirebbe:
var age = person?.Age; // 'age' will be of type 'int?', even if 'person' is not null
https://riptutorial.com/it/home 611
Concatenare l'operatore
L'operatore null-condizionale può essere combinato sui membri e sotto-membri di un oggetto.
L'indice Null-Conditional
Allo stesso modo del ?. operatore, l'operatore indice condizionale null verifica i valori nulli durante
l'indicizzazione in una raccolta che può essere nullo.
Evitare NullReferenceExceptions
https://riptutorial.com/it/home 612
Country = null
}
}
};
Il metodo di estensione può funzionare su riferimenti null , ma puoi usare ?. per null controllare in
ogni caso.
Usando ?. il metodo non verrà attivato per riferimenti null e il tipo è int? :
Questo comportamento è in realtà previsto dal modo in cui il ?. L'operatore lavora: eviterà di
effettuare chiamate al metodo di istanza per istanze nulle, al fine di evitare NullReferenceExceptions
. Tuttavia, la stessa logica si applica al metodo di estensione, nonostante la differenza su come
viene dichiarato il metodo.
Per ulteriori informazioni sul motivo per cui viene chiamato il metodo di estensione nel primo
esempio, consultare i metodi di estensione - documentazione di controllo nullo .
https://riptutorial.com/it/home 613
Capitolo 118: Operazioni stringhe comuni
Examples
Divisione di una stringa in base a un carattere specifico
Substring riporta la stringa in alto da un dato indice, o tra due indici (entrambi inclusi).
Usando System.String.Contains puoi scoprire se una stringa particolare esiste all'interno di una
stringa. Il metodo restituisce un valore booleano, vero se la stringa esiste altrimenti false.
String.Trim()
string q = "{(Hi!*";
string r = q.Trim( '(', '*', '{' ); // "Hi!"
https://riptutorial.com/it/home 614
String.TrimStart() e String.TrimEnd()
string q = "{(Hi*";
string r = q.TrimStart( '{' ); // "(Hi*"
string s = q.TrimEnd( '*' ); // "{(Hi"
Utilizzare il metodo String.Format() per sostituire uno o più elementi nella stringa con la
rappresentazione stringa di un oggetto specificato:
String.Format("Hello {0} Foo {1}", "World", "Bar") //Hello World Foo Bar
string s = "Foo";
string paddedLeft = s.PadLeft(5); // paddedLeft = " Foo" (pads with spaces by default)
string paddedRight = s.PadRight(6, '+'); // paddedRight = "Foo+++"
string noPadded = s.PadLeft(2); // noPadded = "Foo" (original string is never
shortened)
Il metodo String.Join ci aiuterà a costruire una stringa da array / elenco di caratteri o stringa.
Questo metodo accetta due parametri. Il primo è il delimitatore o il separatore che ti aiuterà a
separare ogni elemento dell'array. E il secondo parametro è la matrice stessa.
string delimiter=",";
char[] charArray = new[] { 'a', 'b', 'c' };
string inputString = String.Join(delimiter, charArray);
Uscita : a,b,c se cambiamo il delimiter come "" allora l'uscita diventerà abc .
https://riptutorial.com/it/home 615
Uscita : a|b|c
Uscita : Ram_is_a_boy
Di solito stiamo usando il metodo String.Format per scopi di formattazione, il .ToString viene
solitamente utilizzato per convertire altri tipi in stringa. Possiamo specificare il formato insieme al
metodo ToString mentre la conversione è in corso, quindi possiamo evitare una formattazione
aggiuntiva. Lasciami spiegare come funziona con diversi tipi;
Visual Basic dispone di funzioni Left, Right e Mid che restituiscono caratteri da sinistra, destra e
https://riptutorial.com/it/home 616
centrale di una stringa. Questi metodi non esistono in C #, ma possono essere implementati con
Substring() . Possono essere implementati come metodi di estensione come il seguente:
/// <summary>
/// VB Right function
/// </summary>
/// <param name="stringparam"></param>
/// <param name="numchars"></param>
/// <returns>Right-most numchars characters</returns>
public static string Right( this string stringparam, int numchars )
{
// Handle possible Null or numeric stringparam being passed
stringparam += string.Empty;
/// <summary>
/// VB Mid function - to end of string
/// </summary>
/// <param name="stringparam"></param>
/// <param name="startIndex">VB-Style startindex, 1st char startindex = 1</param>
/// <returns>Balance of string beginning at startindex character</returns>
public static string Mid( this string stringparam, int startindex )
{
// Handle possible Null or numeric stringparam being passed
stringparam += string.Empty;
https://riptutorial.com/it/home 617
// Validate numchars parameter
if (startindex > stringparam.Length)
startindex = stringparam.Length;
/// <summary>
/// VB Mid function - for number of characters
/// </summary>
/// <param name="stringparam"></param>
/// <param name="startIndex">VB-Style startindex, 1st char startindex = 1</param>
/// <param name="numchars">number of characters to return</param>
/// <returns>Balance of string beginning at startindex character</returns>
public static string Mid( this string stringparam, int startindex, int numchars)
{
// Handle possible Null or numeric stringparam being passed
stringparam += string.Empty;
}
}
bool result;
https://riptutorial.com/it/home 618
result = String.IsNullOrEmpty(nullString); // true
result = String.IsNullOrEmpty(emptyString); // true
result = String.IsNullOrEmpty(whitespaceString); // false
result = String.IsNullOrEmpty(tabString); // false
result = String.IsNullOrEmpty(newlineString); // false
result = String.IsNullOrEmpty(nonEmptyString); // false
È possibile utilizzare il metodo Substring per ottenere qualsiasi numero di caratteri da una stringa
in qualsiasi posizione specifica. Tuttavia, se vuoi solo un singolo carattere, puoi usare
l'indicizzatore di stringhe per ottenere un singolo carattere in un dato indice come fai con un array:
string s = "hello";
char c = s[1]; //Returns 'e'
Si noti che il tipo restituito è char , a differenza del metodo Substring che restituisce un tipo di
string .
string s = "hello";
foreach (char c in s)
Console.WriteLine(c);
/********* This will print each character on a new line:
h
e
l
l
o
**********/
https://riptutorial.com/it/home 619
var Number = 15;
Console.WriteLine(Convert.ToString(Number, 16)); //OUTPUT : f
Risultato:
La maggior parte delle volte in cui le persone devono invertire una stringa, lo fanno più o meno
così:
char[] a = s.ToCharArray();
System.Array.Reverse(a);
string r = new string(a);
Tuttavia, ciò di cui queste persone non si rendono conto è che questo è in realtà sbagliato.
E non intendo per il controllo NULL mancante.
Per capire perché è così, dobbiamo prima essere consapevoli del fatto che cosa significhi in realtà
il termine "personaggio".
Riferimento:
Un grafema è una sequenza di uno o più punti di codice che vengono visualizzati come
una singola unità grafica che un lettore riconosce come un singolo elemento del
sistema di scrittura. Ad esempio, sia a che ä sono grafemi, ma possono essere
costituiti da più punti di codice (ad esempio ä possono essere due punti di codice, uno
per il carattere base uno seguito da uno per la diaresi, ma c'è anche un codice
alternativo, legacy, singolo punto che rappresenta questo grafema). Alcuni punti di
codice non fanno mai parte di alcun grafema (es. Il non-falegname a larghezza zero o
gli override direzionali).
https://riptutorial.com/it/home 620
una singola rappresentazione, ad esempio, se quanto sopra ä è un singolo punto di
codice, un font può scegliere di renderlo come due glifi separati, spazialmente
sovrapposti. Per OTF, le tabelle GSUB e GPOS del font contengono informazioni di
sostituzione e posizionamento per far funzionare questo. Un font può contenere più
glifi alternativi per lo stesso grafema.
Il che significa, se si inverte una stringa valida come Les Misérables , che può assomigliare a
questo
selbaêsMe seL
System.Globalization.TextElementEnumerator enumerator =
System.Globalization.StringInfo.GetTextElementEnumerator(s);
while (enumerator.MoveNext())
{
ls.Add((string)enumerator.Current);
}
return ls;
}
// this
private static string ReverseGraphemeClusters(string s)
{
if(string.IsNullOrEmpty(s) || s.Length == 1)
return s;
System.Collections.Generic.List<string> ls = GraphemeClusters(s);
ls.Reverse();
https://riptutorial.com/it/home 621
// s = "noël";
string r = ReverseGraphemeClusters(s);
System.Console.WriteLine(r);
}
E - oh gioia - ti renderai conto che se lo fai correttamente, funzionerà anche per le lingue asiatico /
sud-asiatico / est asiatico (e francese / svedese / norvegese, ecc.) ...
Utilizzando il metodo System.String.Replace , è possibile sostituire parte di una stringa con un'altra
stringa.
Questo metodo può anche essere utilizzato per rimuovere parte di una stringa, utilizzando il
campo String.Empty :
La classe System.String supporta un numero di metodi per la conversione tra caratteri maiuscoli e
minuscoli in una stringa.
Nota: la ragione per utilizzare le versioni invarianti di questi metodi è impedire la produzione di
lettere impreviste specifiche della cultura. Questo è spiegato qui in dettaglio .
Esempio:
Si noti che è possibile scegliere di specificare una cultura specifica durante la conversione in
https://riptutorial.com/it/home 622
lettere minuscole e maiuscole utilizzando i metodi String.ToLower (CultureInfo) e String.ToUpper
(CultureInfo) di conseguenza.
Il metodo System.String.Join consente di concatenare tutti gli elementi in una matrice di stringhe,
utilizzando un separatore specificato tra ciascun elemento:
Concatenazione di stringhe
https://riptutorial.com/it/home 623
Capitolo 119: Parola chiave rendimento
introduzione
Quando si utilizza la parola chiave yield in un'istruzione, si indica che il metodo, l'operatore o
l'opzione di accesso in cui appare è un iteratore. L'utilizzo di yield per definire un iteratore rimuove
la necessità di una classe extra esplicita (la classe che contiene lo stato per un'enumerazione)
quando si implementa il modello IEnumerable e IEnumerator per un tipo di raccolta
personalizzato.
Sintassi
• yield return [TYPE]
• cedimento
Osservazioni
Inserendo la parola chiave yield in un metodo con il tipo restituito di IEnumerable , IEnumerable<T> ,
IEnumerator o IEnumerator<T> indica al compilatore di generare un'implementazione del tipo
restituito ( IEnumerable o IEnumerator ) che, una volta eseguito il loop, esegue il metodo fino a
ciascun "rendimento" per ottenere ogni risultato.
La parola chiave yield è utile quando si desidera restituire "il prossimo" elemento di una sequenza
teoricamente illimitata, quindi calcolare l'intera sequenza in anticipo sarebbe impossibile, o
quando calcolare la sequenza completa di valori prima di tornare comporterebbe una pausa
indesiderata per l'utente .
yield break può essere utilizzata anche per interrompere la sequenza in qualsiasi momento.
Poiché la parola chiave yield richiede un tipo di interfaccia iteratore come tipo restituito, ad
esempio IEnumerable<T> , non è possibile utilizzarlo in un metodo async poiché restituisce un
oggetto Task<IEnumerable<T>> .
Ulteriori letture
• https://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
Examples
Uso semplice
La parola chiave yield viene utilizzata per definire una funzione che restituisce un oggetto
IEnumerable o IEnumerator (nonché le varianti generiche derivate) i cui valori vengono generati
pigramente mentre un chiamante esegue iterazioni sulla raccolta restituita. Maggiori informazioni
sullo scopo nella sezione commenti .
https://riptutorial.com/it/home 624
L'esempio seguente ha un'istruzione return return all'interno di un ciclo for .
Uscita console
4
5
6
...
14
Ogni iterazione del corpo foreach crea una chiamata alla funzione Count iteratore. Ogni chiamata
alla funzione iteratore procede alla successiva esecuzione yield return , che si verifica durante la
successiva iterazione del ciclo for .
Ci sono altri modi per ottenere un IEnumerable<User> da un database SQL, questo dimostra
semplicemente che puoi usare yield per trasformare qualsiasi cosa abbia una semantica di
"sequence of elements" in un IEnumerable<T> che qualcuno può iterare su .
Risoluzione anticipata
https://riptutorial.com/it/home 625
È possibile estendere la funzionalità dei metodi di yield esistenti passando uno o più valori o
elementi che potrebbero definire una condizione di terminazione all'interno della funzione
chiamando un'interruzione di yield break per interrompere l'esecuzione del ciclo interno.
while (true)
{
if (earlyTerminationSet.Contains(curr))
{
// we've hit one of the ending values
yield break;
}
if (curr == Int32.MaxValue)
{
// don't overflow if we get all the way to the end; just stop
yield break;
}
curr++;
}
}
Il metodo sopra riportato itererà da una data posizione di start fino a earlyTerminationSet si
incontra uno dei valori all'interno del primo earlyTerminationSet .
// Iterate from a starting point until you encounter any elements defined as
// terminating elements
var terminatingElements = new HashSet<int>{ 7, 9, 11 };
// This will iterate from 1 until one of the terminating elements is encountered (7)
foreach(var x in CountUntilAny(1,terminatingElements))
{
// This will write out the results from 1 until 7 (which will trigger terminating)
Console.WriteLine(x);
}
Produzione:
1
2
3
4
5
6
https://riptutorial.com/it/home 626
Un metodo iteratore non viene eseguito fino a quando il valore di ritorno non viene enumerato. È
quindi vantaggioso affermare le precondizioni al di fuori dell'iteratore.
Produzione:
1
2
3
4
5
6
7
8
9
10
Quando un metodo usa yield per generare un enumerabile, il compilatore crea una macchina a
stati che, una volta iterata, eseguirà il codice fino a un yield . Quindi restituisce l'articolo restituito
e salva il suo stato.
Ciò significa che non si scopriranno argomenti non validi (passaggio null ecc.) Quando si chiama
https://riptutorial.com/it/home 627
il metodo per la prima volta (poiché ciò crea la macchina di stato), solo quando si tenta di
accedere al primo elemento (perché solo allora il codice all'interno del il metodo viene eseguito
dalla macchina di stato). Racchiudendolo in un metodo normale che prima controlla gli argomenti
è possibile controllarli quando viene chiamato il metodo. Questo è un esempio di veloce
fallimento.
Quando si utilizza C # 7+, la funzione CountCore può essere opportunamente nascosta nella
funzione Count come funzione locale . Vedi l'esempio qui .
Valutazione pigra
Solo quando l'istruzione foreach sposta sull'elemento successivo, il blocco iteratore valuta fino alla
successiva dichiarazione di yield .
https://riptutorial.com/it/home 628
}
Questo produrrà:
Inizia l'iterazione
All'interno dell'iteratore: 0
Dentro foreach: 0
All'interno di iteratore: 1
Dentro foreach: 1
All'interno di iteratore: 2
Dentro foreach: 2
Visualizza la demo
Come conseguenza:
Data la funzione:
Quando si chiama:
https://riptutorial.com/it/home 629
var enumerator = Numbers().GetEnumerator();
enumerator.MoveNext();
Console.WriteLine(enumerator.Current);
enumerator.Dispose();
}
Quindi stampa:
Visualizza la demo
Quando si chiama:
enumerator.MoveNext();
Console.WriteLine(enumerator.Current);
enumerator.MoveNext();
Console.WriteLine(enumerator.Current);
enumerator.Dispose();
}
Quindi stampa:
1
2
Finalmente giustiziato
Visualizza la demo
Mentre la parola chiave yield può essere utilizzata per creare direttamente un IEnumerable<T> , può
anche essere utilizzata esattamente nello stesso modo per creare un IEnumerator<T> . L'unica cosa
che cambia è il tipo di ritorno del metodo.
Questo può essere utile se vogliamo creare la nostra classe che implementa IEnumerable<T> :
https://riptutorial.com/it/home 630
// This method returns an IEnumerator<T>, rather than an IEnumerable<T>
// But the yield syntax and usage is identical.
public IEnumerator<T> GetEnumerator()
{
foreach(var item in _wrapped)
{
Console.WriteLine("Yielding: " + item);
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
(Si noti che questo particolare esempio è solo illustrativo e potrebbe essere implementato in modo
più pulito con un singolo metodo iteratore che restituisce un oggetto IEnumerable<T> .)
Stimolante valutazione
La parola chiave yield consente una valutazione lazy della collezione. Il caricamento forzato
dell'intera collezione in memoria si chiama valutazione entusiasta .
IEnumerable<int> myMethod()
{
for(int i=0; i <= 8675309; i++)
{
yield return i;
}
}
...
// define the iterator
var it = myMethod.Take(3);
// force its immediate evaluation
// list will contain 0, 1, 2
var list = it.ToList();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics; // also add reference to System.Numberics
namespace ConsoleApplication33
{
class Program
https://riptutorial.com/it/home 631
{
private static IEnumerable<BigInteger> Fibonacci()
{
BigInteger prev = 0;
BigInteger current = 1;
while (true)
{
yield return current;
var next = prev + current;
prev = current;
current = next;
}
}
Come funziona sotto il cofano (consiglio di decompilare il file .exe risultante nello strumento IL
Disaambler):
Si noti inoltre che il 10001 ° numero è lungo 468 byte. La macchina a stati salva solo current
variabili current e prev come campi. Mentre se vorremmo salvare tutti i numeri nella sequenza dal
primo al 10000, la dimensione della memoria consumata sarà di oltre 4 megabyte. Quindi la
valutazione pigra, se usata correttamente, può ridurre l'impronta della memoria in alcuni casi.
L'uso della yield break rispetto alla break potrebbe non essere così ovvio come si potrebbe
pensare. Ci sono molti cattivi esempi su Internet in cui l'uso dei due è intercambiabile e in realtà
https://riptutorial.com/it/home 632
non dimostra la differenza.
La parte confusa è che entrambe le parole chiave (o frasi chiave) hanno senso solo all'interno di
cicli ( foreach , while ...) Quindi quando scegliere l'una rispetto all'altra?
È importante rendersi conto che una volta che si utilizza la parola chiave yield in un metodo, si
trasforma effettivamente il metodo in un iteratore . L'unico scopo di tale metodo è quindi di iterare
su una collezione finita o infinita e produrre (produrre) i suoi elementi. Una volta che lo scopo è
soddisfatto, non c'è motivo di continuare l'esecuzione del metodo. A volte, accade naturalmente
con l'ultima parentesi di chiusura del metodo } . Ma a volte, vuoi terminare prematuramente il
metodo. In un normale metodo (non iterativo) useresti la parola chiave return . Ma non puoi usare
return in un iteratore, devi usare yield break . In altre parole, l' yield break per un iteratore
equivale al return di un metodo standard. Mentre l'istruzione break termina semplicemente il ciclo
più vicino.
/// <summary>
/// Yields numbers from 0 to 9
/// </summary>
/// <returns>{0,1,2,3,4,5,6,7,8,9}</returns>
public static IEnumerable<int> YieldBreak()
{
for (int i = 0; ; i++)
{
if (i < 10)
{
// Yields a number
yield return i;
}
else
{
// Indicates that the iteration has ended, everything
// from this line on will be ignored
yield break;
}
}
yield return 10; // This will never get executed
}
/// <summary>
/// Yields numbers from 0 to 10
/// </summary>
/// <returns>{0,1,2,3,4,5,6,7,8,9,10}</returns>
public static IEnumerable<int> Break()
{
for (int i = 0; ; i++)
{
if (i < 10)
{
// Yields a number
yield return i;
}
else
{
// Terminates just the loop
https://riptutorial.com/it/home 633
break;
}
}
// Execution continues
yield return 10;
}
https://riptutorial.com/it/home 634
Capitolo 120: parole
introduzione
Le parole chiave sono identificatori predefiniti e riservati con un significato speciale per il
compilatore. Non possono essere usati come identificatori nel tuo programma senza il prefisso @ .
Ad esempio, @if è un identificatore legale ma non la parola chiave if .
Osservazioni
C # ha una collezione predefinita di "parole chiave" (o parole riservate) che hanno ciascuna una
funzione speciale. Queste parole non possono essere utilizzate come identificatori (nomi per
variabili, metodi, classi, ecc.) A meno che non siano preceduti da @ .
• abstract
• as
• base
• bool
• break
• byte
• case
• catch
• char
• checked
• class
• const
• continue
• decimal
• default
• delegate
• do
• double
• else
• enum
• event
• explicit
• extern
• false
• finally
• fixed
• float
• for
• foreach
• goto
• if
• implicit
• in
• int
• interface
• internal
• is
https://riptutorial.com/it/home 635
• lock
• long
• namespace
• new
• null
• object
• operator
• out
• override
• params
• private
• protected
• public
• readonly
• ref
• return
• sbyte
• sealed
• short
• sizeof
• stackalloc
• static
• string
• struct
• switch
• this
• throw
• true
• try
• typeof
• uint
• ulong
• unchecked
• unsafe
• ushort
• using (direttiva)
• using (dichiarazione)
• virtual
• void
• volatile
• when
• while
Oltre a questi, C # utilizza anche alcune parole chiave per fornire un significato specifico nel
codice. Sono chiamati parole chiave contestuali. Le parole chiave contestuali possono essere
utilizzate come identificatori e non devono essere precedute da prefisso @ quando vengono
utilizzate come identificatori.
• add
• alias
• ascending
• async
• await
• descending
• dynamic
https://riptutorial.com/it/home 636
• from
• get
• global
• group
• into
• join
• let
• nameof
• orderby
• partial
• remove
• select
• set
• value
• var
• where
• yield
Examples
stackalloc
La parola chiave stackalloc crea una regione di memoria nello stack e restituisce un puntatore
all'inizio di tale memoria. La memoria allocata nello stack viene automaticamente rimossa quando
viene chiuso l'ambito in cui è stato creato.
Come con tutti i puntatori in C # non ci sono limiti di controllo su letture e compiti. La lettura oltre i
limiti della memoria allocata avrà risultati imprevedibili - potrebbe accedere a qualche posizione
arbitraria all'interno della memoria o potrebbe causare un'eccezione di violazione di accesso.
//Allocate 1 byte
byte* ptr = stackalloc byte[1];
//Unpredictable results...
ptr[10] = 1;
ptr[-1] = 2;
La memoria allocata nello stack viene automaticamente rimossa quando viene chiuso l'ambito in
cui è stato creato. Ciò significa che non si dovrebbe mai restituire la memoria creata con
stackalloc o conservarla oltre la durata dell'ambito.
https://riptutorial.com/it/home 637
unsafe IntPtr Leak() {
//Allocate some memory on the stack
var ptr = stackalloc byte[1024];
stackalloc può essere usato solo quando si dichiarano e si inizializzano variabili. Quanto segue
non è valido:
byte* ptr;
...
ptr = stackalloc byte[1024];
Osservazioni:
stackalloc deve essere usato solo per ottimizzare le prestazioni (sia per il calcolo che per
l'interoperabilità). Ciò è dovuto al fatto che:
• Il garbage collector non è necessario in quanto la memoria viene allocata nello stack
piuttosto che nell'heap - la memoria viene rilasciata non appena la variabile esce dallo scope
• È più veloce allocare memoria nello stack anziché nell'heap
• Aumentare la possibilità di colpi di cache sulla CPU a causa della località dei dati
volatile
L'aggiunta della parola chiave volatile a un campo indica al compilatore che il valore del campo
può essere modificato da più thread separati. Lo scopo principale della parola chiave volatile è
impedire le ottimizzazioni del compilatore che presuppongono solo l'accesso a thread singolo.
L'utilizzo di volatile garantisce che il valore del campo sia il valore più recente disponibile e che il
valore non sia soggetto alla memorizzazione nella cache dei valori non volatili.
È buona norma contrassegnare tutte le variabili che possono essere utilizzate da più thread come
volatile per prevenire comportamenti imprevisti a causa di ottimizzazioni dietro le quinte.
Considera il seguente blocco di codice:
https://riptutorial.com/it/home 638
// the compiler will optimize this to y = 15
var y = x + 10;
/* the value of x will always be the current value, but y will always be "15" */
Debug.WriteLine("x = " + x + ", y = " + y);
}
}
Ora, il compilatore cerca gli usi di lettura del campo x e assicura che il valore corrente del campo
sia sempre recuperato. Ciò garantisce che anche se più thread stanno leggendo e scrivendo in
questo campo, il valore corrente di x viene sempre recuperato.
volatile può essere utilizzato solo su campi all'interno di class o struct . Quanto segue non è
valido :
• tipi di riferimento o parametri di tipo generico noti per essere tipi di riferimento
• tipi primitivi come sbyte , byte , short , ushort , int , uint , char , float e bool
• tipi di enumerazione basati su byte , sbyte , short , ushort , int o uint
• IntPtr e UIntPtr
Osservazioni:
• Il modificatore volatile viene in genere utilizzato per un campo a cui si accede da più thread
https://riptutorial.com/it/home 639
senza utilizzare l'istruzione lock per serializzare l'accesso.
• La parola chiave volatile può essere applicata a campi di tipi di riferimento
• La parola chiave volatile non renderà operativo su primitive a 64 bit su una piattaforma
atomica a 32 bit. Le operazioni interbloccate come Interlocked.Read e Interlocked.Exchange
devono ancora essere utilizzate per un accesso multi-thread sicuro su queste piattaforme.
fisso
L'istruzione fissa corregge la memoria in un'unica posizione. Gli oggetti in memoria di solito si
spostano, questo rende possibile la raccolta dei dati inutili. Ma quando usiamo i puntatori non
sicuri agli indirizzi di memoria, quella memoria non deve essere spostata.
• Usiamo l'istruzione fixed per assicurare che il garbage collector non rilasci i dati di stringa.
Risolto Variabili
fixed può essere usato solo sui campi di una struct (deve essere usato anche in un contesto non
sicuro).
predefinito
Per classi, interfacce, delegate, array, default(TheType) null (come int?) E tipi di puntatore, il
default(TheType) restituisce null :
class MyClass {}
Debug.Assert(default(MyClass) == null);
Debug.Assert(default(string) == null);
struct Coordinates
{
https://riptutorial.com/it/home 640
public int X { get; set; }
public int Y { get; set; }
}
struct MyStruct
{
public string Name { get; set; }
public Coordinates Location { get; set; }
public Coordinates? SecondLocation { get; set; }
public TimeSpan Duration { get; set; }
}
default(T)può essere particolarmente utile quando T è un parametro generico per il quale non è
presente alcun vincolo per decidere se T è un tipo di riferimento o un tipo di valore, ad esempio:
sola lettura
La parola chiave readonly è un modificatore di campo. Quando una dichiarazione di campo include
un modificatore di readonly , le assegnazioni a quel campo possono avvenire solo come parte
della dichiarazione o in un costruttore della stessa classe.
La parola chiave readonly è diversa dalla parola chiave const . Un campo const può essere
inizializzato solo alla dichiarazione del campo. Un campo di readonly può essere inizializzato o alla
dichiarazione o in un costruttore. Pertanto, i campi di readonly possono avere valori diversi a
seconda del costruttore utilizzato.
class Person
{
readonly string _name;
readonly string _surname = "Surname";
Person(string name)
https://riptutorial.com/it/home 641
{
_name = name;
}
void ChangeName()
{
_name = "another name"; // Compile error
_surname = "another surname"; // Compile error
}
}
//In code
come
Per l'espansione di cui sopra, il compilatore genera codice tale che l' expression sarà valutata solo
una volta e utilizzerà un controllo di tipo dinamico singolo (a differenza dei due nell'esempio sopra
riportato).
as può essere utile quando si aspetta un argomento per facilitare diversi tipi. In particolare,
concede all'utente più opzioni - piuttosto che controllare ogni possibilità con is prima del casting, o
semplicemente lanciare e catturare le eccezioni. È consigliabile utilizzare "come" quando si
esegue il casting / controllo di un oggetto che causerà solo una penalità di annullamento. L'utilizzo
is di controllare, quindi il cast causerà due penalità di annullamento.
https://riptutorial.com/it/home 642
quanto il suo scopo è più chiaro per il lettore.
Poiché una chiamata a as può produrre null , controllare sempre il risultato di evitare un
NullReferenceException .
Esempio di utilizzo
Ciò è utile quando si esegue l'override della funzione Equals nelle classi personalizzate.
class MyCustomClass
{
Verifica se un oggetto è compatibile con un determinato tipo, cioè se un oggetto è un'istanza del
tipo BaseInterface o un tipo che deriva da BaseInterface :
interface BaseInterface {}
class BaseClass : BaseInterface {}
class DerivedClass : BaseClass {}
https://riptutorial.com/it/home 643
Console.WriteLine(d is DerivedClass); // True
Console.WriteLine(d is BaseClass); // True
Console.WriteLine(d is BaseInterface); // True
Console.WriteLine(d is object); // True
Console.WriteLine(d is string); // False
Se l'intento del cast è quello di utilizzare l'oggetto, è buona norma utilizzare il as parola chiave'
interface BaseInterface {}
class BaseClass : BaseInterface {}
class DerivedClass : BaseClass {}
if(d is BaseClass){
var castedD = (BaseClass)d;
castedD.Method(); // valid, but not best practice
}
if(asD!=null){
asD.Method(); //prefered method since you incur only one unboxing penalty
}
7.0
tipo di
const
https://riptutorial.com/it/home 644
const è usato per rappresentare valori che non cambieranno mai per tutta la durata del
programma. Il suo valore è costante dalla fase di compilazione , a differenza della parola chiave
readonly , il cui valore è costante dal tempo di esecuzione.
Ad esempio, poiché la velocità della luce non cambierà mai, possiamo memorizzarla in una
costante.
Questo è essenzialmente uguale alla return mass * 299792458 * 299792458 , in quanto il compilatore
sostituirà direttamente c con il suo valore costante.
Di conseguenza, c non può essere modificato una volta dichiarato. Quanto segue produrrà un
errore in fase di compilazione:
Una costante può essere preceduta dagli stessi modificatori di accesso dei metodi:
const membri const sono static per natura. Tuttavia, l'uso static esplicito non è permesso.
Questi non possono essere preceduti da una parola chiave private o public , poiché sono
implicitamente locali rispetto al metodo in cui sono definiti.
Non tutti i tipi possono essere utilizzati in una dichiarazione const . I tipi di valori consentiti sono i
tipi predefiniti sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal ,
bool e tutti i tipi enum . Provare a dichiarare membri const con altri tipi di valore (come TimeSpan o
Guid ) fallirà in fase di compilazione.
Per la speciale string tipo di riferimento predefinita, le costanti possono essere dichiarate con
qualsiasi valore. Per tutti gli altri tipi di riferimento, le costanti possono essere dichiarate ma
https://riptutorial.com/it/home 645
devono sempre avere il valore null .
Poiché i valori const sono noti in fase di compilazione, sono consentiti come etichette case in
un'istruzione switch , come argomenti standard per parametri facoltativi, come argomenti per
l'attribuzione di specifiche e così via.
Se i valori const vengono utilizzati tra diversi assembly, è necessario prestare attenzione con il
controllo delle versioni. Ad esempio, se l'assembly A definisce un public const int MaxRetries = 3;
e l'assembly B usa quella costante, quindi se il valore di MaxRetries viene in seguito modificato in 5
nell'assembly A (che viene quindi ricompilato), tale modifica non sarà effettiva nell'assembly B a
meno che l' assembly B non venga ricompilato (con un riferimento alla nuova versione di A).
Per questo motivo, se un valore può cambiare nelle revisioni future del programma e se il valore
deve essere visibile pubblicamente, non dichiarare tale valore const se non si è certi che tutti gli
assembly dipendenti verranno ricompilati ogni volta che qualcosa viene modificato. L'alternativa
sta usando static readonly invece di const , che viene risolto in fase di runtime.
namespace
La parola chiave namespace è un costrutto organizzativo che ci aiuta a capire come è organizzato
un codebase. I namespace in C # sono spazi virtuali piuttosto che essere in una cartella fisica.
namespace StackOverflow
{
namespace Documentation
{
namespace CSharp.Keywords
{
public class Program
{
public static void Main()
{
Console.WriteLine(typeof(Program).Namespace);
//StackOverflow.Documentation.CSharp.Keywords
}
}
}
}
}
namespace StackOverflow.Documentation.CSharp.Keywords
{
public class Program
{
public static void Main()
{
Console.WriteLine(typeof(Program).Namespace);
//StackOverflow.Documentation.CSharp.Keywords
https://riptutorial.com/it/home 646
}
}
}
try , catch , finally e throw ti permettono di gestire le eccezioni nel tuo codice.
// The code within the try block will be executed. If an exception occurs during execution of
// this code, execution will pass to the catch block corresponding to the exception type.
try
{
processor.Process(input);
}
// If a FormatException is thrown during the try block, then this catch block
// will be executed.
catch (FormatException ex)
{
// Throw is a keyword that will manually throw an exception, triggering any catch block
that is
// waiting for that exception type.
throw new InvalidOperationException("Invalid input", ex);
}
// catch can be used to catch all or any specific exceptions. This catch block,
// with no type specified, catches any exception that hasn't already been caught
// in a prior catch block.
catch
{
LogUnexpectedException();
throw; // Re-throws the original exception.
}
// The finally block is executed after all try-catch blocks have been; either after the try
has
// succeeded in running all commands or after all exceptions have been caught.
finally
{
processor.Dispose();
}
Nota: la parola chiave return può essere utilizzata nel blocco try e il blocco finally verrà
comunque eseguito (appena prima di tornare). Per esempio:
try
{
connection.Open();
return connection.Get(query);
}
finally
{
connection.Close();
}
L'istruzione connection.Close() verrà eseguita prima del risultato della connection.Get(query) viene
restituito.
https://riptutorial.com/it/home 647
Continua
Passa immediatamente il controllo alla successiva iterazione del costrutto del loop che lo
racchiude (for, foreach, do, while):
Produzione:
5
6
7
8
9
Produzione:
un
B
c
d
ref, fuori
Le parole chiave ref e out sì che un argomento venga passato per riferimento, non per valore. Per
i tipi di valore, ciò significa che il valore della variabile può essere modificato dal destinatario.
int x = 5;
ChangeX(ref x);
// The value of x could be different now
https://riptutorial.com/it/home 648
Per i tipi di riferimento, l'istanza nella variabile non può essere modificata solo (come nel caso
senza ref ), ma può anche essere sostituita del tutto:
La principale differenza tra la parola chiave out e ref è che ref richiede che la variabile venga
inizializzata dal chiamante, mentre out passa tale responsabilità al destinatario.
Per utilizzare un parametro out , sia la definizione del metodo sia il metodo di chiamata devono
utilizzare esplicitamente la parola chiave out .
int number = 1;
Console.WriteLine("Before AddByRef: " + number); // number = 1
AddOneByRef(ref number);
Console.WriteLine("After AddByRef: " + number); // number = 2
SetByOut(out number);
Console.WriteLine("After SetByOut: " + number); // number = 34
Quanto segue non si compila, perché out parametri out devono avere un valore assegnato prima
che il metodo ritorni (si compilerebbe invece usando ref ):
out parola chiave out può essere utilizzata anche nei parametri di tipo generico quando si
definiscono interfacce e delegati generici. In questo caso, la parola chiave out specifica che il
parametro type è covariante.
La covarianza consente di utilizzare un tipo più derivato rispetto a quello specificato dal
parametro generico. Ciò consente la conversione implicita di classi che implementano
interfacce varianti e la conversione implicita di tipi di delegati. Covarianza e
controvarianza sono supportate per i tipi di riferimento, ma non sono supportate per i
tipi di valore. - MSDN
https://riptutorial.com/it/home 649
//if we have an interface like this
interface ICovariant<out R> { }
selezionato, deselezionato
Dal momento che la maggior parte delle operazioni aritmetiche vengono eseguite su valori che
non sono grandi o abbastanza piccoli da eccedere, la maggior parte delle volte non è necessario
definire esplicitamente un blocco come checked . È necessario prestare attenzione quando si
eseguono operazioni aritmetiche su input non limitati che possono causare un overflow, ad
esempio quando si esegue l'aritmetica in funzioni ricorsive o mentre si immette l'input dell'utente.
Uno degli usi più comuni per unchecked è l'implementazione di una sovrascrittura personalizzata
per object.GetHashCode() , un tipo di checksum. Puoi vedere l'uso della parola chiave nelle risposte
a questa domanda: qual è il miglior algoritmo per un System.Object.GetHashCode sottoposto a
override? .
https://riptutorial.com/it/home 650
aritmetica che provoca un overflow genera una OverflowException generata.
I blocchi selezionati e deselezionati non influiscono sui metodi chiamati, solo gli operatori chiamati
direttamente nel metodo corrente. Ad esempio, Enum.ToObject() , Convert.ToInt32() e gli operatori
definiti dall'utente non sono interessati dai contesti personalizzati selezionati / non selezionati.
vai a
goto può essere utilizzato per passare a una riga specifica all'interno del codice, specificata da
un'etichetta.
goto come:
Etichetta:
void InfiniteHello()
{
sayHello:
Console.WriteLine("Hello!");
goto sayHello;
}
Caso clinico:
switch (GetRequestedPermission())
{
case Permissions.Read:
GrantReadAccess();
break;
https://riptutorial.com/it/home 651
case Permissions.Write:
GrantWriteAccess();
goto case Permissions.Read; //People with write access also get read
}
Eccezione Riprova
var exCount = 0;
retry:
try
{
//Do work
}
catch (IOException)
{
exCount++;
if (exCount < 3)
{
Thread.Sleep(100);
goto retry;
}
throw;
}
Simile a molte lingue, l'uso della parola chiave goto è sconsigliato tranne i casi di seguito.
• Pausa multi-livello LINQ può essere usato spesso, ma di solito ha prestazioni peggiori.
• Deallocazione delle risorse quando si lavora con oggetti di basso livello non aperti. In C #, gli
oggetti di basso livello dovrebbero essere normalmente racchiusi in classi separate.
• Macchine a stati finiti, ad esempio parser; utilizzato internamente dal compilatore generato
async / await state machine.
enum
La parola chiave enum dice al compilatore che questa classe eredita dalla classe astratta Enum ,
senza che il programmatore debba ereditarlo esplicitamente. Enum è un discendente di ValueType ,
che è inteso per l'uso con un insieme distinto di costanti con nome.
https://riptutorial.com/it/home 652
public enum DaysOfWeek
{
Monday,
Tuesday,
}
In questo esempio ho omesso un valore per 0, di solito è una cattiva pratica. Un enum avrà sempre
un valore predefinito prodotto dalla conversione esplicita (YourEnumType) 0 , dove YourEnumType è il
tipo enume dichiarato. Senza un valore di 0 definito, un enum non avrà un valore definito all'avvio.
Il tipo di enum predefinito di base è int , è possibile modificare il tipo sottostante a qualsiasi tipo
integrale incluso byte , sbyte , short , ushort , int , uint , long e ulong . Di seguito è riportato un
enum con byte tipo sottostante:
Si noti inoltre che è possibile convertire in / dal tipo sottostante semplicemente con un cast:
Per questi motivi è meglio controllare sempre se un enum è valido quando si espongono le funzioni
della libreria:
// ...
}
base
La parola chiave di base viene utilizzata per accedere ai membri da una classe base. Viene
comunemente utilizzato per chiamare le implementazioni di base dei metodi virtuali o per
https://riptutorial.com/it/home 653
specificare quale costruttore di base deve essere chiamato.
Scegliere un costruttore
https://riptutorial.com/it/home 654
Assert.AreEqual(1, NormalMethod());
Assert.AreEqual(1, base.VirtualMethod());
}
}
// Notice that the call to NormalMethod below still returns the value
// from the extreme base class even though the method has been overridden
// in the child class.
Assert.AreEqual(1, NormalMethod());
}
}
per ciascuno
foreach viene utilizzato per scorrere gli elementi di una matrice o gli elementi all'interno di una
raccolta che implementa IEnumerable ✝.
Questo uscirà
"Ciao mondo!"
"Come stai oggi?"
"Addio"
È possibile uscire dal ciclo foreach in qualsiasi momento utilizzando la parola chiave break o
passare alla successiva iterazione utilizzando la parola chiave continue .
https://riptutorial.com/it/home 655
{
// Skip if 2
if (number == 2)
continue;
// Stop iteration if 5
if (number == 5)
break;
// Prints: 1, 3, 4,
Si noti che l'ordine di iterazione è garantito solo per determinate raccolte come matrici ed List ,
ma non è garantito per molte altre raccolte.
✝ Mentre IEnumerable viene in genere utilizzato per indicare le raccolte enumerabili, foreach richiede
solo che la raccolta esponga pubblicamente il metodo object GetEnumerator() , che deve restituire
un oggetto che espone il metodo bool MoveNext() e l' object Current { get; } proprietà.
params
params consente a un parametro del metodo di ricevere un numero variabile di argomenti, vale a
dire zero, uno o più argomenti sono consentiti per quel parametro.
return total;
}
Questo metodo può ora essere chiamato con una lista tipica di argomenti int , o una matrice di
interi.
deve apparire al massimo una volta e se usato, deve essere l' ultimo nella lista degli
params
argomenti, anche se il tipo successivo è diverso da quello dell'array.
Fare attenzione quando si sovraccaricano le funzioni quando si utilizza la parola chiave params . C
# preferisce abbinare sovraccarichi più specifici prima di ricorrere al tentativo di usare
sovraccarichi con params . Ad esempio se hai due metodi:
https://riptutorial.com/it/home 656
static double Add(params double[] numbers)
{
Console.WriteLine("Add with array of doubles");
double total = 0.0;
foreach (double number in numbers)
{
total += number;
}
return total;
}
rompere
In un ciclo (for, foreach, do, while) l'istruzione break interrompe l'esecuzione del ciclo più interno e
ritorna al codice dopo di esso. Inoltre può essere utilizzato con yield in cui specifica che un
iteratore è giunto al termine.
L'istruzione break viene anche utilizzata nei costrutti del caso di commutazione per uscire da un
caso o da un segmento predefinito.
switch(a)
https://riptutorial.com/it/home 657
{
case 5:
Console.WriteLine("a was 5!");
break;
default:
Console.WriteLine("a was something else!");
break;
}
Nelle istruzioni switch, la parola chiave 'break' è richiesta alla fine di ogni dichiarazione di caso.
Ciò è contrario ad alcune lingue che consentono di "passare attraverso" alla successiva
dichiarazione del caso nella serie. I rimedi per questo includevano le istruzioni "goto" o
l'impilamento sequenziale delle dichiarazioni "case".
Il codice seguente darà i numeri 0, 1, 2, ..., 9 e l'ultima riga non verrà eseguita. yield break
indica la fine della funzione (non solo un loop).
Nota che a differenza di altri linguaggi, non c'è modo di etichettare una particolare interruzione in
C #. Ciò significa che nel caso di cicli annidati, verrà interrotto solo il ciclo più interno:
Se vuoi uscire dal ciclo esterno qui, puoi utilizzare una delle diverse strategie, ad esempio:
• Una dichiarazione goto per saltare fuori dall'intera struttura del ciclo.
• Una specifica variabile di flag ( shouldBreak nell'esempio seguente) che può essere verificata
alla fine di ogni iterazione del ciclo esterno.
• Rifattorizzare il codice per utilizzare un'istruzione return nel corpo del ciclo più interno o
evitare del tutto l'intera struttura del ciclo annidato.
https://riptutorial.com/it/home 658
bool shouldBreak = false;
while(comeCondition)
{
while(otherCondition)
{
if (conditionToBreak)
{
// Either tranfer control flow to the label below...
goto endAllLooping;
if(shouldBreakNow)
{
break; // Break out of outer loop if flag was set to true
}
}
astratto
Una classe contrassegnata con la parola chiave abstract non può essere istanziata.
Una classe deve essere contrassegnata come astratta se contiene membri astratti o se eredita
membri astratti che non implementa. Una classe può essere contrassegnata come astratta anche
se non sono coinvolti membri astratti.
Le classi astratte vengono solitamente utilizzate come classi base quando alcune parti
dell'implementazione devono essere specificate da un altro componente.
Animal cat = new Cat(); // Allowed due to Cat deriving from Animal
https://riptutorial.com/it/home 659
cat.MakeSound(); // will print out "Meov meov"
Animal dog = new Dog(); // Allowed due to Dog deriving from Animal
dog.MakeSound(); // will print out "Bark bark"
Animal animal = new Animal(); // Not allowed due to being an abstract class
Un metodo, una proprietà o un evento contrassegnati con la parola chiave abstract indica che
l'implementazione per tale membro dovrebbe essere fornita in una sottoclasse. Come accennato
in precedenza, i membri astratti possono apparire solo in classi astratte.
galleggiante
float è un alias per il tipo di dati .NET System.Single . Consente di memorizzare i numeri in virgola
mobile a precisione singola IEEE 754. Questo tipo di dati è presente in mscorlib.dll cui fa
riferimento implicitamente ogni progetto C # quando vengono creati.
Notazione :
float f = 0.1259;
var f1 = 0.7895f; // f is literal suffix to represent float values
Va notato che il tipo float spesso causa errori di arrotondamento significativi. Nelle
applicazioni in cui la precisione è importante, devono essere considerati altri tipi di dati.
Doppio
double
https://riptutorial.com/it/home 660
è un alias del tipo di dati .NET System.Double . Rappresenta un numero a virgola mobile a 64 bit a
doppia precisione. Questo tipo di dati è presente in mscorlib.dll cui viene fatto implicitamente
riferimento in qualsiasi progetto C #.
Notazione :
decimale
decimal è un alias del tipo di dati .NET System.Decimal . Rappresenta una parola chiave indica un
tipo di dati a 128 bit. Rispetto ai tipi a virgola mobile, il tipo decimale ha più precisione e un
intervallo più piccolo, il che lo rende appropriato per i calcoli finanziari e monetari. Questo tipo di
dati è presente in mscorlib.dll cui viene fatto implicitamente riferimento in qualsiasi progetto C #.
Notazione :
uint
Un intero senza segno , o uint , è un tipo di dati numerico che può contenere solo interi positivi.
Come suggerisce il nome, rappresenta un numero intero a 32 bit senza segno. La stessa parola
chiave uint è un alias per il tipo di sistema di tipo comune System.UInt32 . Questo tipo di dati è
presente in mscorlib.dll , a cui fa riferimento implicitamente ogni progetto C # quando vengono
creati. Occupa quattro byte di spazio di memoria.
Gli interi senza segno possono contenere qualsiasi valore compreso tra 0 e 4.294.967.295.
Nota: secondo Microsoft , si consiglia di utilizzare il tipo di dati int ove possibile in quanto il tipo di
https://riptutorial.com/it/home 661
dati uint non è conforme a CLS.
Questo
Il this parola chiave si riferisce all'istanza corrente di classe (oggetto). In questo modo si possono
distinguere due variabili con lo stesso nome, una a livello di classe (un campo) e una essendo un
parametro (o una variabile locale) di un metodo.
public MyClass {
int a;
void set_a(int a)
{
//this.a refers to the variable defined outside of the method,
//while a refers to the passed parameter.
this.a = a;
}
}
Altri usi della parola chiave sono concatenamento di sovraccarichi di costruttori non statici :
Se non v'è alcun conflitto con una variabile locale o un parametro, si tratta di una questione di stile
se utilizzare this o no, così this.MemberOfType e MemberOfType sarebbero equivalenti in quel caso.
Vedi anche la parola chiave di base .
Si noti che se un metodo di estensione deve essere chiamato in questa istanza, this è richiesto.
Ad esempio se ci si trova all'interno di un metodo non statico di una classe che implementa
IEnumerable<> e si desidera chiamare il Count dell'estensione di prima, è necessario utilizzare:
https://riptutorial.com/it/home 662
per
Questo esempio mostra come for può essere usato per scorrere i caratteri di una stringa:
Produzione:
H
e
l
l
o
Tutte le espressioni che definiscono una dichiarazione for sono facoltative; ad esempio, la
seguente istruzione è usata per creare un ciclo infinito:
for( ; ; )
{
// Your code here
}
La sezione di initializer può contenere più variabili, purché siano dello stesso tipo. La sezione
delle condition può essere costituita da qualsiasi espressione che può essere valutata da un bool .
E la sezione iterator può eseguire più azioni separate da una virgola:
Produzione:
Ciao
hello1
hello12
https://riptutorial.com/it/home 663
Live Demo su .NET Fiddle
mentre
L'operatore while esegue iterazioni su un blocco di codice fino a quando la query condizionale è
uguale a false o il codice viene interrotto con un'istruzione goto , return , break o throw .
Esempio:
int i = 0;
while (i++ < 5)
{
Console.WriteLine("While is on loop number {0}.", i);
}
Produzione:
Un ciclo while è Entry Controlled , poiché la condizione viene verificata prima dell'esecuzione
del blocco di codice allegato. Ciò significa che il ciclo while non eseguirà le sue istruzioni se la
condizione è falsa.
bool a = false;
while (a == true)
{
Console.WriteLine("This will never be printed.");
}
Dare una condizione while senza provvedere a renderlo falso ad un certo punto si tradurrà in un
ciclo infinito o infinito. Per quanto possibile, questo dovrebbe essere evitato, tuttavia, ci possono
essere alcune circostanze eccezionali quando ne hai bisogno.
while (true)
{
//...
}
https://riptutorial.com/it/home 664
while (true)
{
// ...
}
for(;;)
{
// ...
}
in
{
:label
// ...
goto label;
}
Si noti che un ciclo while può avere qualsiasi condizione, non importa quanto complessa, purché
valuti (o restituisca) un valore booleano (bool). Può anche contenere una funzione che restituisce
un valore booleano (in quanto tale una funzione valuta lo stesso tipo di un'espressione come `a ==
x '). Per esempio,
while (AgriculturalService.MoreCornToPick(myFarm.GetAddress()))
{
myFarm.PickCorn();
}
ritorno
MSDN: l'istruzione return termina l'esecuzione del metodo in cui appare e restituisce il
controllo al metodo di chiamata. Può anche restituire un valore opzionale. Se il metodo
è di tipo vuoto, l'istruzione return può essere omessa.
nel
https://riptutorial.com/it/home 665
a) Come parte della sintassi in un'istruzione foreach o come parte della sintassi in una query LINQ
b) Nel contesto di interfacce generiche e tipi di delegati generici indica la controvarianza per il
parametro di tipo in questione:
c) Nel contesto della query LINQ fa riferimento alla raccolta che viene interrogata
utilizzando
Esistono due tipi di using dell'utilizzo di parole chiave, using statement e using directive :
1. usando la dichiarazione :
La parola chiave using assicura che gli oggetti che implementano l'interfaccia IDisposable
siano disposti correttamente dopo l'uso. C'è un argomento separato per l' istruzione using
2. usando la direttiva
La direttiva using ha tre usi, vedere la pagina msdn per la direttiva using . C'è un argomento
separato per la direttiva using .
sigillato
class A { }
sealed class B : A { }
class C : B { } //error : Cannot derive from the sealed class
Quando applicato a un metodo virtual (o proprietà virtuale), il modificatore sealed impedisce che
questo metodo (proprietà) venga sovrascritto nelle classi derivate.
public class A
{
public sealed override string ToString() // Virtual method inherited from class Object
{
return "Do not override me!";
}
}
https://riptutorial.com/it/home 666
public class B: A
{
public override string ToString() // Compile time error
{
return "An attempt to override";
}
}
taglia di
statico
Il modificatore static viene utilizzato per dichiarare un membro statico, che non ha bisogno di
essere istanziato per poter accedere, ma è invece accessibile semplicemente attraverso il suo
nome, ad es. DateTime.Now .
static può essere utilizzato con classi, campi, metodi, proprietà, operatori, eventi e costruttori.
Mentre un'istanza di una classe contiene una copia separata di tutti i campi di istanza della classe,
c'è solo una copia di ogni campo statico.
class A
{
static public int count = 0;
public A()
{
count++;
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
A b = new A();
A c = new A();
https://riptutorial.com/it/home 667
Console.WriteLine(A.count); // 3
}
}
Il modificatore statico può anche essere utilizzato per dichiarare un costruttore statico per una
classe, per inizializzare dati statici o eseguire codice che deve essere chiamato una sola volta. I
costruttori statici vengono chiamati prima che la classe venga referenziata per la prima volta.
class A
{
static public DateTime InitializationTime;
// Static constructor
static A()
{
InitializationTime = DateTime.Now;
// Guaranteed to only run once
Console.WriteLine(InitializationTime.ToString());
}
}
Una static class è contrassegnata con la parola chiave static e può essere utilizzata come
contenitore utile per un insieme di metodi che funzionano sui parametri, ma non necessariamente
richiedono l'associazione con un'istanza. A causa della natura static della classe, non può essere
istanziato, ma può contenere un static constructor . Alcune funzionalità di una static class
includono:
https://riptutorial.com/it/home 668
public static int Double(int value)
{
return value + value;
}
}
anche tutte le funzioni, proprietà o membri all'interno della classe devono essere dichiarati statici.
Nessuna istanza della classe può essere creata. In sostanza, una classe statica consente di
creare gruppi di funzioni raggruppate in modo logico.
Dal momento che C # 6 static può essere utilizzato anche a fianco using importare soci e metodi
statici. Possono essere usati quindi senza nome della classe.
using System;
svantaggi
Mentre le classi statiche possono essere incredibilmente utili, vengono fornite con i loro
avvertimenti:
• Una volta che la classe statica è stata chiamata, la classe viene caricata in memoria e non
può essere eseguita attraverso il garbage collector finché non viene scaricato AppDomain
che ospita la classe statica.
int
https://riptutorial.com/it/home 669
int è un alias per System.Int32 , che è un tipo di dati per interi a 32 bit con segno. Questo tipo di
dati può essere trovato in mscorlib.dll cui fa riferimento implicitamente ogni progetto C # quando
vengono creati.
lungo
La parola chiave long viene utilizzata per rappresentare interi a 64 bit con segno. È un alias per il
tipo di dati System.Int64 presente in mscorlib.dll , a cui viene fatto implicitamente riferimento ogni
progetto C # quando vengono creati.
Qualsiasi variabile lunga può essere dichiarata sia esplicitamente che implicitamente:
ulong
Parola chiave utilizzata per numeri interi a 64 bit senza segno. Rappresenta il tipo di dati
System.UInt64 trovato in mscorlib.dll cui fa riferimento implicitamente ogni progetto C # quando
vengono creati.
Intervallo: da 0 a 18.446.744.073.709.551.615
dinamico
La parola chiave dynamic viene utilizzata con oggetti digitati dinamicamente . Gli oggetti dichiarati
come dynamic escludono i controlli statici in fase di compilazione e vengono invece valutati in fase
di runtime.
using System;
using System.Dynamic;
Console.WriteLine(info.Another);
https://riptutorial.com/it/home 670
// 456
Console.WriteLine(info.DoesntExist);
// Throws RuntimeBinderException
L'esempio seguente utilizza la dynamic con la libreria di Newtonsoft Json.NET, per leggere
facilmente i dati da un file JSON deserializzato.
try
{
string json = @"{ x : 10, y : ""ho""}";
dynamic deserializedJson = JsonConvert.DeserializeObject(json);
int x = deserializedJson.x;
string y = deserializedJson.y;
// int z = deserializedJson.z; // throws RuntimeBinderException
}
catch (RuntimeBinderException e)
{
// This exception is thrown when a property
// that wasn't assigned to a dynamic variable is used
}
Esistono alcune limitazioni associate alla parola chiave dinamica. Uno di questi è l'uso di metodi di
estensione. Nell'esempio seguente viene aggiunto un metodo di estensione per la stringa:
SayHello .
Il primo approccio sarà chiamarlo come al solito (come per una stringa):
virtuale e override
La parola chiave virtual consente a un metodo, proprietà, indicizzatore o evento di essere
sovrascritto da classi derivate e presenta un comportamento polimorfico. (I membri non sono
https://riptutorial.com/it/home 671
virtuali di default in C #)
Per sovrascrivere un membro, la parola chiave override viene utilizzata nelle classi derivate. (Nota
la firma dei membri deve essere identica)
Il comportamento polimorfico dei membri virtuali significa che quando viene invocato, il membro
effettivo che viene eseguito viene determinato in fase di esecuzione anziché in fase di
compilazione. Il membro che sovrascrive nella classe più derivata l'oggetto particolare è un'istanza
di sarà quella eseguita.
In breve, l'oggetto può essere dichiarato di tipo BaseClass in fase di compilazione ma se in fase di
esecuzione è un'istanza di DerivedClass il membro sottoposto a override verrà eseguito:
nuovo
Poiché solo i membri definiti come virtual sono sovrascrivibili e polimorfici, una classe derivata
che ridefinisce un membro non virtuale potrebbe portare a risultati imprevisti.
https://riptutorial.com/it/home 672
Console.WriteLine("Foo from BaseClass");
}
}
Quando ciò accade, il membro eseguito viene sempre determinato al momento della compilazione
in base al tipo dell'oggetto.
Questo di solito è un incidente (quando un membro viene aggiunto al tipo base dopo che uno
identico è stato aggiunto al tipo derivato) e in questi scenari viene generato un avviso del
compilatore CS0108 .
Se è stato intenzionale, la new parola chiave viene utilizzata per sopprimere l'avviso del
compilatore (e informare gli altri sviluppatori delle tue intenzioni!). il comportamento rimane lo
stesso, la new parola chiave sopprime solo l'avviso del compilatore.
https://riptutorial.com/it/home 673
L'uso dell'override non è facoltativo
A differenza di C ++, l'uso della parola chiave override non è facoltativo:
public class A
{
public virtual void Foo()
{
}
}
public class B : A
{
public void Foo() // Generates CS0108
{
}
}
L'esempio precedente causa inoltre un avviso CS0108 , poiché B.Foo() non sovrascrive
automaticamente A.Foo() . Aggiungi override quando l'intenzione è di ignorare la classe base e
causare comportamenti polimorfici, aggiungere new quando si desidera un comportamento non
polimorfico e risolvere la chiamata utilizzando il tipo statico. Quest'ultimo dovrebbe essere usato
con cautela, in quanto potrebbe causare grave confusione.
public class A
{
public void Foo()
{
}
}
public class B : A
{
public override void Foo() // Error: Nothing to override
{
}
}
public class A
{
public void Foo()
{
Console.WriteLine("A");
https://riptutorial.com/it/home 674
}
}
public class B : A
{
public new virtual void Foo()
{
Console.WriteLine("B");
}
}
Ora tutti gli oggetti con un riferimento statico di B (e le sue derivate) usano il polimorfismo per
risolvere Foo() , mentre i riferimenti di A usano A.Foo() .
A a = new A();
a.Foo(); // Prints "A";
a = new B();
a.Foo(); // Prints "A";
B b = new B();
b.Foo(); // Prints "B";
public class A
{
private virtual void Foo() // Error: virtual methods cannot be private
{
}
}
asincrono, attendi
La parola chiave await stata aggiunta come parte della release C # 5.0 supportata da Visual
Studio 2012 in poi. Sfrutta la Task Parallel Library (TPL) che ha reso la multi-threading
relativamente più semplice. Le parole chiave async e await sono utilizzate in coppia con la stessa
funzione mostrata di seguito. La parola chiave await viene utilizzata per sospendere l'esecuzione
del metodo asincrono corrente fino a quando l'attività asincrona attesa viene completata e / oi
relativi risultati restituiti. Per utilizzare la parola chiave await , il metodo che lo utilizza deve essere
contrassegnato con la parola chiave async .
L'uso async con void è fortemente scoraggiato. Per maggiori informazioni puoi guardare qui .
Esempio:
https://riptutorial.com/it/home 675
Console.WriteLine("Starting a useless process...");
Stopwatch stopwatch = Stopwatch.StartNew();
int delay = await UselessProcessAsync(1000);
stopwatch.Stop();
Console.WriteLine("A useless process took {0} milliseconds to execute.",
stopwatch.ElapsedMilliseconds);
}
Produzione:
La parola chiave pairs async e await può essere omessa se un Task o Task<T> return method
restituisce solo una singola operazione asincrona.
5.0
6.0
carbonizzare
Un carattere è una singola lettera memorizzata all'interno di una variabile. È un tipo di valore
incorporato che richiede due byte di spazio di memoria. Rappresenta il tipo di dati System.Char
https://riptutorial.com/it/home 676
trovato in mscorlib.dll cui fa riferimento implicitamente ogni progetto C # quando vengono creati.
1. char c = 'c';
2. char c = '\u0063'; //Unicode
3. char c = '\x0063'; //Hex
4. char c = (char)99;//Integral
Un char può essere implicitamente convertito in ushort, int, uint, long, ulong, float, double, o
decimal e restituirà il valore intero di quel char.
ushort u = c;
restituisce 99 ecc.
Tuttavia, non ci sono conversioni implicite da altri tipi a char. Invece devi castarli.
ushort u = 99;
char c = (char)u;
serratura
lock fornisce thread-safety per un blocco di codice, in modo che sia accessibile da un solo thread
all'interno dello stesso processo. Esempio:
Console.ReadKey();
}
Task.Delay(3000);
Console.WriteLine("Done Delaying");
Console.WriteLine("Leaving");
}
}
Output:
Entered
Done Delaying
https://riptutorial.com/it/home 677
Leaving
Entered
Done Delaying
Leaving
Entered
Done Delaying
Leaving
Casi d'uso:
Ogni volta che si dispone di un blocco di codice che potrebbe produrre effetti collaterali se
eseguito da più thread contemporaneamente. La parola chiave di blocco insieme a un oggetto di
sincronizzazione condiviso ( _objLock nell'esempio) può essere utilizzata per impedirlo.
Si noti che _objLock non può essere null e più thread che eseguono il codice devono utilizzare la
stessa istanza di oggetto (rendendola un campo static o utilizzando la stessa istanza di classe
per entrambi i thread)
Dal lato del compilatore, la parola chiave lock è uno zucchero sintattico che viene sostituito da
Monitor.Enter(_lockObj); e Monitor.Exit(_lockObj); . Quindi se sostituisci il blocco circondando il
blocco di codice con questi due metodi, otterresti gli stessi risultati. È possibile visualizzare il
codice effettivo in zucchero sintattico in C # - esempio di blocco
nullo
Come espressione, può essere usato per assegnare il riferimento null alle variabili dei tipi sopra
citati:
object a = null;
string b = null;
int? c = null;
List<int> d = null;
Ai tipi di valori non annullabili non può essere assegnato un riferimento null. Tutti i seguenti
incarichi non sono validi:
int a = null;
float b = null;
decimal c = null;
Il riferimento null non deve essere confuso con istanze valide di vari tipi come:
https://riptutorial.com/it/home 678
• il numero zero ( 0 , 0f , 0m )
• il carattere null ( '\0' )
interno
La parola chiave internal è un modificatore di accesso per i membri di tipo e tipo. Tipi interni o
membri sono accessibili solo all'interno di file nello stesso assembly
utilizzo:
Modificatori di accesso
pubblico
privato
protetta
https://riptutorial.com/it/home 679
interno
protetto interno
dove
wherepuò servire a due scopi in C #: digita il vincolo in un argomento generico e filtra le query
LINQ.
T è chiamato parametro di tipo. La definizione della classe può imporre vincoli sui tipi reali che
possono essere forniti per T.
• tipo di valore
• tipo di riferimento
• costruttore predefinito
• eredità e attuazione
tipo di valore
In questo caso possono essere fornite solo struct s (questo include i tipi di dati 'primitivi' come int
, boolean ecc.)
tipo di riferimento
https://riptutorial.com/it/home 680
public class Cup<T> where T : class
{
// ...
}
costruttore predefinito
Saranno consentiti solo i tipi che contengono un costruttore predefinito. Ciò include i tipi di valore
e le classi che contengono un costruttore predefinito (senza parametri)
eredità e attuazione
Possono essere forniti solo i tipi che ereditano da una determinata classe base o implementano
una determinata interfaccia.
https://riptutorial.com/it/home 681
È possibile specificare più vincoli per un argomento di tipo:
int[] nums = { 5, 2, 1, 3, 9, 8, 6, 7, 2, 0 };
var query =
from num in nums
where num < 5
select num;
extern
La parola chiave extern viene utilizzata per dichiarare metodi implementati esternamente. Può
essere utilizzato insieme all'attributo DllImport per chiamare nel codice non gestito utilizzando i
servizi di interoperabilità. che in questo caso arriverà con static modificatore static
Per esempio:
using System.Runtime.InteropServices;
public class MyClass
{
[DllImport("User32.dll")]
private static extern int SetForegroundWindow(IntPtr point);
Questo può anche essere usato per definire un alias di assembly esterno. che ci permette di fare
https://riptutorial.com/it/home 682
riferimento a diverse versioni degli stessi componenti dal singolo assemblaggio.
Per fare riferimento a due assembly con gli stessi nomi di tipo completi, è necessario specificare
un alias al prompt dei comandi, come indicato di seguito:
/r:GridV1=grid.dll
/r:GridV2=grid20.dll
Questo crea gli alias esterni GridV1 e GridV2. Per utilizzare questi alias all'interno di un
programma, consultali usando la parola chiave extern. Per esempio:
bool
Parola chiave per la memorizzazione dei valori booleani true e false . bool è un alias di
System.Boolean.
Per un bool per consentire valori nulli deve essere inizializzato come bool ?.
quando
Il when una parola chiave viene aggiunta in C # 6 e viene utilizzata per il filtraggio delle eccezioni.
Prima dell'introduzione della parola chiave when , si poteva avere una clausola catch per ogni tipo
di eccezione; con l'aggiunta della parola chiave, ora è possibile un controllo più dettagliato.
A when expression è associata a un ramo catch e solo se la condizione when è true , la clausola
catch verrà eseguita. È possibile avere diverse clausole di catch con gli stessi tipi di classi di
eccezioni e diverse when condizioni.
// exception filter
https://riptutorial.com/it/home 683
catch (Exception ex) when (ex.Message.Contains("when"))
{
Console.WriteLine("Caught an exception with when");
}
private void Method1() { throw new Exception("message for exception with when"); }
private void Method2() { throw new Exception("message for general exception"); }
CatchException(Method1);
CatchException(Method2);
non verificato
Per esempio:
Senza la parola chiave non unchecked , nessuna delle due operazioni di aggiunta verrà compilata.
Quando è utile?
Questo è utile in quanto può aiutare ad accelerare i calcoli che sicuramente non avranno overflow
dal momento che il controllo dell'overflow richiede tempo, o quando un overflow / underflow è un
comportamento desiderato (ad esempio, quando si genera un codice hash).
vuoto
Un metodo con un tipo restituito di vuoto può ancora avere la parola chiave return nel suo corpo.
https://riptutorial.com/it/home 684
Ciò è utile quando si desidera uscire dall'esecuzione del metodo e restituire il flusso al chiamante:
if (condition)
return;
In un contesto non sicuro, un tipo può essere un tipo di puntatore, un tipo di valore o un tipo di
riferimento. Una dichiarazione del tipo puntatore è solitamente type* identifier , dove il tipo è un
tipo noto, ad esempio int* myInt , ma può anche essere void* identifier , in cui il tipo è
sconosciuto.
L'istruzione if viene utilizzata per controllare il flusso del programma. Un'istruzione if identifica
quale istruzione eseguire in base al valore di un'espressione Boolean .
int a = 4;
if(a % 2 == 0)
{
Console.WriteLine("a contains an even number");
}
// output: "a contains an even number"
L' if può anche avere una clausola else , che verrà eseguita nel caso in cui la condizione sia
falsa:
int a = 5;
if(a % 2 == 0)
{
Console.WriteLine("a contains an even number");
}
else
{
Console.WriteLine("a contains an odd number");
}
// output: "a contains an odd number"
https://riptutorial.com/it/home 685
int a = 9;
if(a % 2 == 0)
{
Console.WriteLine("a contains an even number");
}
else if(a % 3 == 0)
{
Console.WriteLine("a contains an odd number that is a multiple of 3");
}
else
{
Console.WriteLine("a contains an odd number");
}
// output: "a contains an odd number that is a multiple of 3"
È anche importante nei casi in cui condizioni precedenti assicurano che è "sicuro" valutare quelli
successivi. Per esempio:
fare
L'operatore do esegue iterazioni su un blocco di codice fino a quando una query condizionale è
uguale a false. Il ciclo do-while può anche essere interrotto da un'istruzione goto , return , break o
throw .
https://riptutorial.com/it/home 686
do { blocco di codice; } while ( condizione );
Esempio:
int i = 0;
do
{
Console.WriteLine("Do is on loop number {0}.", i);
} while (i++ < 5);
Produzione:
A differenza del ciclo while , il ciclo do-while è Exit Controlled . Ciò significa che il ciclo do-while
eseguirà le sue istruzioni almeno una volta, anche se la condizione non riesce la prima volta.
bool a = false;
do
{
Console.WriteLine("This will be printed once, even if a is false.");
} while (a == true);
operatore
La maggior parte degli operatori integrati (inclusi gli operatori di conversione) può essere
sovraccaricata utilizzando la parola chiave operator insieme ai modificatori public e static .
Gli operatori sono disponibili in tre forme: operatori unari, operatori binari e operatori di
conversione.
Gli operatori unari e binari richiedono almeno un parametro dello stesso tipo del tipo contenente e
alcuni richiedono un operatore di corrispondenza complementare.
https://riptutorial.com/it/home 687
public int Y { get; }
Esempio
https://riptutorial.com/it/home 688
struct
Un tipo di struct è un tipo di valore che viene in genere utilizzato per incapsulare piccoli gruppi di
variabili correlate, come le coordinate di un rettangolo o le caratteristiche di un articolo in un
inventario.
namespace ConsoleApplication1
{
struct Point
{
public int X;
public int Y;
class Program
{
static void Main()
{
var point1 = new Point {X = 10, Y = 20};
// it's not a reference but value type
var point2 = point1;
point2.X = 777;
point2.Y = 888;
point1.Display(nameof(point1)); // point1: X = 10, Y = 20
point2.Display(nameof(point2)); // point2: X = 777, Y = 888
ReadKey();
}
}
}
Le strutture possono anche contenere costruttori, costanti, campi, metodi, proprietà, indicizzatori,
operatori, eventi e tipi annidati, sebbene se siano richiesti più di questi membri, dovresti prendere
in considerazione la creazione di una classe invece.
TENERE CONTO
definire una struct invece di una classe se le istanze del tipo sono piccole e comunemente di
https://riptutorial.com/it/home 689
breve durata o sono comunemente incorporate in altri oggetti.
EVITARE
definire una struttura a meno che il tipo abbia tutte le seguenti caratteristiche:
• Rappresenta logicamente un singolo valore, simile ai tipi primitivi (int, double, ecc.)
• Ha una dimensione dell'istanza inferiore a 16 byte.
• È immutabile.
• Non dovrà essere incassato frequentemente.
interruttore
L'istruzione switch è un'istruzione di controllo che seleziona una sezione switch da eseguire da un
elenco di candidati. Una dichiarazione switch include una o più sezioni switch. Ogni sezione
switch contiene una o più etichette case seguite da una o più istruzioni. Se nessuna etichetta case
contiene un valore corrispondente, il controllo viene trasferito alla sezione default , se ce n'è uno.
Caso fall-through non è supportato in C #, in senso stretto. Tuttavia, se 1 o più etichette del case
sono vuote, l'esecuzione seguirà il codice del successivo blocco del case che contiene il codice.
Ciò consente il raggruppamento di più case con la stessa implementazione. Nell'esempio
seguente, se il month uguale a 12, il codice nel case 2 verrà eseguito poiché le etichette del case 12
1 e 2 sono raggruppate. Se un blocco del case non è vuoto, deve essere presente break prima della
successiva etichetta del case , altrimenti il compilatore segnala un errore.
switch (month)
{
case 12:
case 1:
case 2:
Console.WriteLine("Winter");
break;
case 3:
case 4:
case 5:
Console.WriteLine("Spring");
break;
case 6:
case 7:
case 8:
Console.WriteLine("Summer");
break;
case 9:
case 10:
case 11:
Console.WriteLine("Autumn");
break;
default:
Console.WriteLine("Incorrect month index");
break;
}
Un case può essere etichettato solo da un valore noto al momento della compilazione (es. 1 , "str"
https://riptutorial.com/it/home 690
, Enum.A ), quindi una variable non è un'etichetta case valida, ma un valore const o un valore Enum è
(così come qualsiasi valore letterale).
interfaccia
interface IProduct
{
decimal Price { get; }
}
pericoloso
La parola chiave unsafe può essere utilizzata nelle dichiarazioni del tipo o del metodo o per
dichiarare un blocco in linea.
Lo scopo di questa parola chiave è di abilitare l'uso del sottoinsieme non sicuro di C # per il blocco
in questione. Il sottoinsieme non sicuro include funzionalità come puntatori, allocazione dello
stack, array di tipo C e così via.
Il codice non sicuro non è verificabile ed è per questo che il suo utilizzo è scoraggiato. La
compilazione di codice non sicuro richiede il passaggio di un passaggio al compilatore C #. Inoltre,
il CLR richiede che l'assembly in esecuzione abbia piena fiducia.
Nonostante queste limitazioni, il codice non sicuro ha degli usi validi per rendere alcune operazioni
più performanti (ad esempio l'indicizzazione degli array) o più semplici (ad es. Interop con alcune
librerie non gestite).
https://riptutorial.com/it/home 691
//Since we passed in "the address of i", this becomes "i *= i"
}
Mentre lavoriamo con i puntatori, possiamo modificare direttamente i valori delle locazioni di
memoria, piuttosto che doverli affrontare per nome. Si noti che questo spesso richiede l'uso della
parola chiave fissa per prevenire possibili corruzioni della memoria in quanto il garbage collector
sposta le cose intorno (altrimenti, si potrebbe ottenere l' errore CS0212 ). Poiché non è possibile
scrivere su una variabile che è stata "riparata", spesso è necessario avere un secondo puntatore
che inizi a puntare alla stessa posizione del primo.
void Main()
{
int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
UnsafeSquareArray(intArray);
foreach(int i in intArray)
Console.WriteLine(i);
}
Produzione:
https://riptutorial.com/it/home 692
4
9
16
25
36
49
64
81
100
unsafe consente inoltre l'uso di stackalloc che allocherà memoria nello stack come _alloca nella
libreria di runtime C. Possiamo modificare l'esempio precedente per usare stackalloc come segue:
//FIRST OPTION:
int* p = seedArray; // we don't want to lose where the array starts, so we
// create a shadow copy of the pointer
for(int i=1; i<=len; i++)
*p++ = i;
//end of first option
//SECOND OPTION:
for(int i=0; i<len; i++)
seedArray[i] = i+1;
//end of second option
UnsafeSquareArray(seedArray, len);
for(int i=0; i< len; i++)
Console.WriteLine(seedArray[i]);
}
//Now that we are dealing directly in pointers, we don't need to mess around with
// "fixed", which dramatically simplifies the code
unsafe static void UnsafeSquareArray(int* p, int len)
{
for (int i = 0; i < len; i++)
*p *= *p++;
}
implicito
https://riptutorial.com/it/home 693
{
public int Numerator { get; } = numerator;
public int Denominator { get; } = denominator;
// ...
public static implicit operator double(Fraction f)
{
return f.Numerator / (double) f.Denominator;
}
public static implicit operator Fraction(int i)
{
return new Fraction(i, 1);
}
}
vero falso
Il sovraccarico dell'operatore falso era utile prima del C # 2.0, prima dell'introduzione dei tipi
Nullable .
Un tipo che sovraccarica l'operatore true , deve anche sovraccaricare l'operatore false .
stringa
stringè un alias del tipo di dati .NET System.String , che consente di memorizzare testo
(sequenze di caratteri).
Notazione:
string a = "Hello";
var b = "world";
var f = new string(new []{ 'h', 'i', '!' }); // hi!
Ogni carattere nella stringa è codificato in UTF-16, il che significa che ogni carattere richiederà
almeno 2 byte di spazio di archiviazione.
https://riptutorial.com/it/home 694
USHORT
Un tipo numerico utilizzato per memorizzare interi positivi a 16 bit. ushort è un alias per
System.UInt16 e occupa 2 byte di memoria.
ushort a = 50; // 50
ushort b = 65536; // Error, cannot be converted
ushort c = unchecked((ushort)65536); // Overflows (wraps around to 0)
sbyte
Un tipo numerico utilizzato per memorizzare interi con segno a 8 bit. sbyte è un alias per
System.SByte e occupa 1 byte di memoria. Per l'equivalente senza segno, usa il byte .
L'intervallo valido è compreso tra -127 e 127 (l'avanzo viene utilizzato per memorizzare il segno).
var
Una variabile locale implicitamente tipizzata che è fortemente tipizzata come se l'utente avesse
dichiarato il tipo. A differenza di altre dichiarazioni variabili, il compilatore determina il tipo di
variabile che rappresenta in base al valore che gli viene assegnato.
var i = 10; // implicitly typed, the compiler must determine what type of variable this is
int i = 10; // explicitly typed, the type of variable is explicitly stated to the compiler
// Note that these both represent the same type of variable (int) with the same value (10).
A differenza di altri tipi di variabili, le definizioni di variabili con questa parola chiave devono essere
inizializzate quando dichiarate. Ciò è dovuto alla parola chiave var che rappresenta una variabile
tipizzata implicitamente.
var i;
i = 10;
La parola chiave var può anche essere utilizzata per creare nuovi tipi di dati al volo. Questi nuovi
tipi di dati sono noti come tipi anonimi . Sono abbastanza utili, in quanto consentono a un utente di
definire un insieme di proprietà senza dover dichiarare esplicitamente qualsiasi tipo di tipo di
oggetto per primo.
https://riptutorial.com/it/home 695
var a = new { number = 1, text = "hi" };
DoStuff(result);
}
return false;
}
delegare
I delegati sono tipi che rappresentano un riferimento a un metodo. Sono usati per passare metodi
come argomenti ad altri metodi.
I delegati possono contenere metodi statici, metodi di istanza, metodi anonimi o espressioni
lambda.
class DelegateExample
{
public void Run()
{
https://riptutorial.com/it/home 696
//using class method
InvokeDelegate( WriteToConsole );
Quando si assegna un metodo a un delegato è importante notare che il metodo deve avere lo
stesso tipo di ritorno e anche i parametri. Ciò differisce dal sovraccarico del metodo "normale", in
cui solo i parametri definiscono la firma del metodo.
evento
Semplice esempio
void RaiseEvent()
{
var ev = DataChangeEvent;
if(ev != null)
{
ev(this, EventArgs.Empty);
}
}
}
https://riptutorial.com/it/home 697
public class Client
{
public void Client(Server server)
{
// client subscribes to the server's DataChangeEvent
server.DataChangeEvent += server_DataChanged;
}
Riferimento MSDN
parziale
La parola chiave partial può essere utilizzata durante la definizione del tipo di classe, struct o
interfaccia per consentire la divisione della definizione del tipo in più file. Questo è utile per
incorporare nuove funzionalità nel codice generato automaticamente.
File1.cs
namespace A
{
public partial class Test
{
public string Var1 {get;set;}
}
}
File2.cs
namespace A
{
public partial class Test
{
public string Var2 {get;set;}
}
}
Nota: una classe può essere suddivisa in un numero qualsiasi di file. Tuttavia, tutte le
dichiarazioni devono trovarsi nello stesso spazio dei nomi e nello stesso assembly.
I metodi possono anche essere dichiarati parziali usando la parola chiave partial . In questo caso
un file conterrà solo la definizione del metodo e un altro file conterrà l'implementazione.
Un metodo parziale ha la propria firma definita in una parte di un tipo parziale e la sua
implementazione definita in un'altra parte del tipo. I metodi parziali consentono ai
progettisti di classi di fornire hook di metodo, simili ai gestori di eventi, che gli
sviluppatori possono decidere di implementare o meno. Se lo sviluppatore non fornisce
un'implementazione, il compilatore rimuove la firma al momento della compilazione. Le
https://riptutorial.com/it/home 698
seguenti condizioni si applicano ai metodi parziali:
- MSDN
File1.cs
namespace A
{
public partial class Test
{
public string Var1 {get;set;}
public partial Method1(string str);
}
}
File2.cs
namespace A
{
public partial class Test
{
public string Var2 {get;set;}
public partial Method1(string str)
{
Console.WriteLine(str);
}
}
}
Nota: anche il tipo contenente il metodo parziale deve essere dichiarato parziale.
https://riptutorial.com/it/home 699
Capitolo 121: Per iniziare: Json con C #
introduzione
Il seguente argomento introdurrà un modo per lavorare con Json usando il linguaggio C # e
concetti di serializzazione e deserializzazione.
Examples
Semplice esempio di JSON
{
"id": 89,
"name": "Aldous Huxley",
"type": "Author",
"books":[{
"name": "Brave New World",
"date": 1932
},
{
"name": "Eyeless in Gaza",
"date": 1936
},
{
"name": "The Genius and the Goddess",
"date": 1955
}]
}
Per lavorare con Json usando C #, è necessario utilizzare Newtonsoft (.net library). Questa libreria
fornisce metodi che consentono al programmatore di serializzare e deserializzare oggetti e altro
ancora. C'è un tutorial se vuoi sapere i dettagli sui suoi metodi e usi.
Se utilizzi Visual Studio, vai su Strumenti / Gestore pacchetti Nuget / Gestisci pacchetto su
soluzione / e digita "Newtonsoft" nella barra di ricerca e installa il pacchetto. Se non hai NuGet,
questo tutorial dettagliato potrebbe aiutarti.
Implementazione C #
Prima di leggere del codice, è importante comprendere i concetti principali che aiuteranno a
programmare le applicazioni usando json.
https://riptutorial.com/it/home 700
convertito nel json precedente.
Per risolvere questo problema, è importante trasformare la struttura di JSON in classi per
utilizzare i processi già descritti. Se si utilizza Visual Studio, è possibile trasformare
automaticamente un json in una classe semplicemente selezionando "Modifica / Incolla speciale /
Incolla JSON come classi" e incollando la struttura di JSON.
using Newtonsoft.Json;
class Author
{
[JsonProperty("id")] // Set the variable below to represent the json attribute
public int id; //"id"
[JsonProperty("name")]
public string name;
[JsonProperty("type")]
public string type;
[JsonProperty("books")]
public Book[] books;
class Book
{
[JsonProperty("name")]
public string name;
[JsonProperty("date")]
public DateTime date;
}
serializzazione
Il metodo ".SerializeObject" riceve come parametro un oggetto tipo , quindi puoi inserire qualcosa.
deserializzazione
È possibile ricevere un json da qualsiasi luogo, un file o anche un server, in modo che non sia
https://riptutorial.com/it/home 701
incluso nel seguente codice.
Il metodo ".DeserializeObject" deserializza " jsonExample " in un oggetto " Autore ". Questo è il
motivo per cui è importante impostare le variabili json nella definizione delle classi, in modo che il
metodo acceda per riempirlo.
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
namespace Framework
{
public static class IGUtilities
{
public static string Serialization(this T obj)
{
string data = JsonConvert.SerializeObject(obj);
return data;
}
https://riptutorial.com/it/home 702
Capitolo 122: Polimorfismo
Examples
Un altro esempio di polimorfismo
Il polimorfismo è uno dei pilastri dell'OOP. Poly deriva da un termine greco che significa "forme
multiple".
Di seguito è riportato un esempio che mostra Polymorphism. La classe Vehicle assume più forme
come classe base.
https://riptutorial.com/it/home 703
}
Di seguito è riportato lo snippet di codice in cui viene visualizzato Polymorphism. L'oggetto viene
creato per il tipo di base Vehicle utilizza un vehicle variabile sulla linea 1. Chiama il metodo della
classe base Display() sulla linea 2 e visualizza l'output come mostrato.
Alla riga 3, l'oggetto vehicle è indirizzato alla classe derivata Ducati e chiama il suo metodo
Display() , che visualizza l'uscita come mostrato. Qui viene il polimorfismo, anche se l'oggetto
vehicle è di tipo Vehicle , si chiama il metodo classe derivata Display() come tipo Ducati eredita
dalla classe base Display() metodo, poiché il vehicle oggetto è puntato verso Ducati .
La stessa spiegazione è applicabile quando richiama il metodo Display() del tipo Lamborghini .
Tipi di polimorfismo
Il polimorfismo indica che un'operazione può essere applicata anche a valori di altri tipi.
• Polimorfismo ad hoc:
contiene function overloading . L'obiettivo è che un metodo può essere utilizzato con diversi
tipi senza la necessità di essere generici.
• Polimorfismo parametrico:
è l'uso di tipi generici. Vedi Generics
• subtyping:
ha il target ereditato da una classe per generalizzare una funzionalità simile
Polimorfismo ad hoc
L'obiettivo del Ad hoc polymorphism è quello di creare un metodo, che può essere chiamato da
diversi tipi di dati senza bisogno di conversione di tipo nella chiamata di funzione o generici. Il
seguente metodo (s) sumInt(par1, par2) può essere chiamato con diversi tipi di dati e ha per ogni
https://riptutorial.com/it/home 704
combinazione di tipi una propria implementazione:
return _a + _b;
}
return _a + b;
}
subtyping
Sottotipo è l'uso di ereditare da una classe base per generalizzare un comportamento simile:
https://riptutorial.com/it/home 705
public void refuel()
{
Console.WriteLine("Refueling with petrol");
}
}
Entrambe le classi NormalCar e ElectricCar ora hanno un metodo per fare rifornimento, ma la loro
stessa implementazione. Ecco un esempio:
https://riptutorial.com/it/home 706
Capitolo 123: Presa asincrona
introduzione
Utilizzando socket asincroni, un server può ascoltare le connessioni in entrata e fare qualche altra
logica nel frattempo in contrasto con il socket sincrono quando sono in ascolto bloccano il thread
principale e l'applicazione sta diventando non rispondente e si bloccherà fino a quando un client
non si connetterà.
Osservazioni
Presa e rete
Come accedere a un server al di fuori della mia rete? Questa è una domanda comune e quando
viene posta la domanda è per lo più segnalata come argomento.
Lato server
Sulla rete del tuo server devi portare il tuo router in avanti al tuo server.
IP locale = 192.168.1.115
L'unica cosa che devi cambiare è l'IP. Non vuoi collegarti al tuo indirizzo di loopback ma all'IP
pubblico dalla rete su cui è in esecuzione il tuo server. Questo IP puoi arrivare qui .
Quindi ora crei una richiesta su questo endpoint: 10.10.10.10:1234 se hai fatto la proprietà port
forwarding del router il tuo server e client si connetteranno senza alcun problema.
Invio di dati:
I dati vengono inviati nell'array di byte. Devi mettere i tuoi dati in un array di byte e decomprimerlo
dall'altro lato.
Se hai familiarità con il socket puoi anche provare a crittografare il tuo array di byte prima di
https://riptutorial.com/it/home 707
inviarlo. Ciò impedirà a chiunque di rubare il pacchetto.
Examples
Esempio di socket asincrono (client / server).
Inizia con la creazione di un server che gestirà i client che si connettono e le richieste che
verranno inviate. Quindi crea una classe listener che gestirà questo.
class Listener
{
public Socket ListenerSocket; //This is the socket that will listen to any incoming
connections
public short Port = 1234; // on this port we will listen
public Listener()
{
ListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
}
}
Per prima cosa dobbiamo inizializzare il socket Listener dove possiamo ascoltare tutte le
connessioni. Useremo un socket Tcp per questo usiamo SocketType.Stream. Inoltre,
specifichiamo la porta strega che il server dovrebbe ascoltare
1. ListenerSocket.Bind ();
2. ListenerSocket.Listen (10);
3. ListenerSocket.BeginAccept ();
Il server inizierà ad ascoltare le connessioni in entrata e continuerà con altra logica. Quando
c'è una connessione il server torna a questo metodo ed eseguirà il metodo AcceptCallBack
https://riptutorial.com/it/home 708
{
try
{
MessageBox.Show($"Listening started port:{Port} protocol type:
{ProtocolType.Tcp}");
ListenerSocket.Bind(new IPEndPoint(IPAddress.Any, Port));
ListenerSocket.Listen(10);
ListenerSocket.BeginAccept(AcceptCallback, ListenerSocket);
}
catch(Exception ex)
{
throw new Exception("listening error" + ex);
}
}
1. ListenerSocket.EndAccept ()
2. ClientController.AddClient()
3. ListenerSocket.BeginAccept ()
ListenerSocket.BeginAccept(AcceptCallback, ListenerSocket);
}
catch (Exception ex)
{
throw new Exception("Base Accept error"+ ex);
}
}
Ora abbiamo un socket di ascolto ma come riceviamo i dati inviati dal client che è ciò che mostra il
https://riptutorial.com/it/home 709
prossimo codice.
Prima di creare una classe di ricezione con un costruttore che accetta un Socket come parametro:
Nel prossimo metodo iniziamo con il dare al buffer una dimensione di 4 byte (Int32) o il pacchetto
contiene parti {lunghezza, dati reali}. Quindi i primi 4 byte riserviamo per la lunghezza dei dati il
resto per i dati effettivi.
Successivamente usiamo il metodo BeginReceive () . Questo metodo viene utilizzato per iniziare a
ricevere dai client connessi e quando riceverà i dati eseguirà la funzione ReceiveCallback .
https://riptutorial.com/it/home 710
the socket.
StartReceiving();
}
else
{
Disconnect();
}
}
catch
{
// if exeption is throw check if socket is connected because than you can
startreive again else Dissconect
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
StartReceiving();
}
}
}
class Client
{
public Socket _socket { get; set; }
public ReceivePacket Receive { get; set; }
public int Id { get; set; }
https://riptutorial.com/it/home 711
{
public static List<Client> Clients = new List<Client>();
Connessione al server
Prima di tutto vogliamo creare una classe che collega al server il nome che gli diamo è:
Connettore:
class Connector
{
private Socket _connectingSocket;
}
1. Crea il socket;
3. Ogni ciclo è solo tenendo premuto il thread per 1 secondo, non vogliamo DOS sul server XD
5. Si noti che il client sta tentando di connettersi al PC locale sulla porta 1234.
while (!_connectingSocket.Connected)
{
Thread.Sleep(1000);
try
{
_connectingSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"),
1234));
https://riptutorial.com/it/home 712
}
catch { }
}
SetupForReceiveing();
}
}
Quindi ora abbiamo quasi una finitura o l'applicazione Socket. L'unica cosa che non abbiamo jet è
una classe per inviare un messaggio al server.
Finaly cassa due pulsanti uno per la connessione e l'altro per l'invio di un messaggio:
https://riptutorial.com/it/home 713
Connector tpp = new Connector();
tpp.TryToConnect();
}
Avviso
La classe di ricezione dal server è la stessa della classe di ricezione del client.
Conclusione
Ora hai un server e un client. Puoi lavorare su questo esempio di base. Ad esempio, assicurati
che il server possa anche ricevere file o altri elementi. O inviare un messaggio al cliente. Nel
server hai una lista di clienti così quando ricevi qualcosa che saprai dal cliente da cui proviene.
Risultato finale:
https://riptutorial.com/it/home 714
Leggi Presa asincrona online: https://riptutorial.com/it/csharp/topic/9638/presa-asincrona
https://riptutorial.com/it/home 715
Capitolo 124: Programmazione funzionale
Examples
Func e azione
Func fornisce un supporto per le funzioni anonime parametrizzate. I tipi principali sono gli input e
l'ultimo tipo è sempre il valore restituito.
// square a number.
Func<double, double> square = (x) => { return x * x; };
Gli oggetti azione sono come metodi void quindi hanno solo un tipo di input. Nessun risultato è
inserito nello stack di valutazione.
// right-angled triangle.
class Triangle
{
public double a;
public double b;
public double h;
}
// Pythagorean theorem.
Action<Triangle> pythagoras = (x) =>
x.h = squareroot(square(x.a) + square(x.b));
Immutabilità
https://riptutorial.com/it/home 716
}
Ricordare che disporre di raccolte di sola lettura non rispetta l'immutabilità. Per esempio,
https://riptutorial.com/it/home 717
• Sapere che l'oggetto non può essere modificato rende il codice più facile da capire.
Gli sviluppatori C # ottengono un sacco di eccezioni di riferimento null da gestire. Gli sviluppatori
di F # non lo fanno perché hanno il tipo Option. Un tipo di opzione <> (alcuni preferiscono forse <>
come nome) fornisce un tipo di ritorno Some e None. Rende esplicito che un metodo potrebbe
essere in procinto di restituire un record nullo.
Ad esempio, non puoi leggere quanto segue e sapere se dovrai gestire un valore nullo.
Il codice ora rende esplicito che potremmo avere un record None restituito e il codice boilerplate
da verificare per Some o None è richiesto:
public T Value
{
get
{
https://riptutorial.com/it/home 718
if (!HasValue)
throw new InvalidOperationException();
return _value;
}
}
Per dimostrare quanto sopra avoidNull.csx può essere eseguito con C # REPL.
Come affermato, questa è un'implementazione minima. Una ricerca di pacchetti "Forse" NuGet
mostrerà un buon numero di buone librerie.
Una funzione di ordine superiore è quella che accetta un'altra funzione come argomento o
restituisce una funzione (o entrambe).
Questo è comunemente fatto con lambdas, ad esempio quando si passa un predicato a una
clausola LINQ Where:
La clausola Where () potrebbe ricevere molti predicati diversi che gli conferiscono una notevole
flessibilità.
Collezioni immutabili
https://riptutorial.com/it/home 719
var stack = ImmutableStack.Create<int>();
var stack2 = stack.Push(1); // stack is still empty, stack2 contains 1
var stack3 = stack.Push(2); // stack2 still contains only one, stack3 has 2, 1
• System.Collections.Immutable.ImmutableArray<T>
• System.Collections.Immutable.ImmutableDictionary<TKey,TValue>
• System.Collections.Immutable.ImmutableHashSet<T>
• System.Collections.Immutable.ImmutableList<T>
• System.Collections.Immutable.ImmutableQueue<T>
• System.Collections.Immutable.ImmutableSortedDictionary<TKey,TValue>
• System.Collections.Immutable.ImmutableSortedSet<T>
• System.Collections.Immutable.ImmutableStack<T>
https://riptutorial.com/it/home 720
Capitolo 125: Programmazione orientata agli
oggetti in C #
introduzione
Questo argomento prova a dirci come possiamo scrivere programmi basati sull'approccio OOP.
Ma non proviamo a insegnare il paradigma della programmazione orientata agli oggetti.
Tratteremo i seguenti argomenti: Classi, Proprietà, Ereditarietà, Polimorfismo, Interfacce e così
via.
Examples
Classi:
<>: Richiesto
[]:Opzionale
Non preoccuparti se non riesci a capire l'intera sintassi, acquisiremo familiarità con tutte le sue
parti. Per il primo esempio, considera la seguente classe:
class MyClass
{
int i = 100;
public void getMyValue()
{
Console.WriteLine(this.i);//Will print number 100 in output
}
}
in questa classe creiamo la variabile i con tipo int e con i Modifier di accesso privati predefiniti e il
metodo getMyValue() con i modificatori di accesso pubblico.
https://riptutorial.com/it/home 721
Capitolo 126: Proprietà
Osservazioni
Le proprietà combinano l'archiviazione dei dati di classe dei campi con l'accessibilità dei metodi. A
volte può essere difficile decidere se utilizzare una proprietà, una proprietà che fa riferimento a un
campo o un metodo che fa riferimento a un campo. Come regola generale:
Per quanto riguarda Metodi vs Proprietà, dove è possibile recuperare ( get ) e aggiornare ( set ) un
valore, una proprietà è la scelta migliore. Inoltre, .Net offre molte funzionalità che fanno uso della
struttura di una classe; ad esempio aggiungendo una griglia a un modulo, .Net elenca per default
tutte le proprietà della classe su quel modulo; quindi, per utilizzare al meglio tali convenzioni, è
consigliabile utilizzare le proprietà quando questo comportamento è in genere auspicabile e i
metodi in cui preferiresti che i tipi non vengano aggiunti automaticamente.
Examples
Varie proprietà nel contesto
https://riptutorial.com/it/home 722
}
Pubblico Ottieni
string name;
public string Name
{
get { return this.name; }
}
Set pubblico
string name;
public string Name
{
set { this.name = value; }
}
class Program
{
public static void Main(string[] args)
{
Person aPerson = new Person("Ann Xena Sample", new DateTime(1984, 10, 22));
//example of accessing properties (Id, Name & DOB)
https://riptutorial.com/it/home 723
Console.WriteLine("Id is: \t{0}\nName is:\t'{1}'.\nDOB is: \t{2:yyyy-MM-dd}.\nAge is:
\t{3}", aPerson.Id, aPerson.Name, aPerson.DOB, aPerson.GetAgeInYears());
//example of setting properties
//see how our changes above take effect; note that the Name has been trimmed
Console.WriteLine("Id is: \t{0}\nName is:\t'{1}'.\nDOB is: \t{2:yyyy-MM-dd}.\nAge is:
\t{3}", aPerson.Id, aPerson.Name, aPerson.DOB, aPerson.GetAgeInYears());
https://riptutorial.com/it/home 724
private bool HasHadBirthdayThisYear()
{
bool hasHadBirthdayThisYear = true;
DateTime today = DateTime.UtcNow;
if (today.Month > this.dob.Month)
{
hasHadBirthdayThisYear = true;
}
else
{
if (today.Month == this.dob.Month)
{
hasHadBirthdayThisYear = today.Day > this.dob.Day;
}
else
{
hasHadBirthdayThisYear = false;
}
}
return hasHadBirthdayThisYear;
}
}
Proprietà auto-implementate
https://riptutorial.com/it/home 725
Le proprietà implementate automaticamente sono state introdotte in C # 3.
Una proprietà auto-implementata è dichiarata con un getter e setter vuoto (accessor):
Quando una proprietà auto-implementata è scritta nel tuo codice, il compilatore crea un campo
anonimo privato a cui è possibile accedere solo tramite gli accessors della proprietà.
Le proprietà implementate automaticamente non possono avere alcuna logica nei loro accessor,
ad esempio:
Una proprietà auto-implementata può tuttavia avere diversi modificatori di accesso per i suoi
accessori:
Dichiarazione
Un comune malinteso, in particolare i principianti, è di proprietà di sola readonly è quello
contrassegnato con una parola chiave readonly . Questo non è corretto e in effetti il seguente è un
errore in fase di compilazione :
https://riptutorial.com/it/home 726
Una proprietà è di sola lettura quando ha solo un getter.
public Address(
string zipCode,
string city,
string streetAddress)
{
if (zipCode == null)
throw new ArgumentNullException(nameof(zipCode));
if (city == null)
throw new ArgumentNullException(nameof(city));
if (streetAddress == null)
throw new ArgumentNullException(nameof(streetAddress));
ZipCode = zipCode;
City = city;
StreetAddress = streetAddress;
}
}
https://riptutorial.com/it/home 727
Capitolo 127: puntatori
Osservazioni
Puntatori e unsafe
A causa della loro natura, i puntatori producono codice non verificabile. Pertanto, l'utilizzo di
qualsiasi tipo di puntatore richiede un contesto unsafe .
Il tipo System.IntPtr è un wrapper sicuro attorno a un void* . È inteso come un'alternativa più
conveniente a void* quando non è richiesto altrimenti un contesto non sicuro per eseguire l'attività
a portata di mano.
Examples
Puntatori per l'accesso alla matrice
Questo esempio dimostra come i puntatori possono essere utilizzati per l'accesso di tipo C agli
array C #.
unsafe
{
var buffer = new int[1024];
fixed (int* p = &buffer[0])
{
for (var i = 0; i < buffer.Length; i++)
{
*(p + i) = i;
https://riptutorial.com/it/home 728
}
}
}
La parola chiave unsafe è necessaria perché l'accesso al puntatore non emetterà alcun controllo
sui limiti normalmente emesso quando si accede agli array C # in modo regolare.
La parola chiave fixed dice al compilatore C # di emettere istruzioni per bloccare l'oggetto in un
modo sicuro. Il blocco è necessario per garantire che il garbage collector non sposterà la matrice
in memoria, in quanto ciò invaliderebbe qualsiasi puntatore che punta all'interno dell'array.
L'addizione e la sottrazione nei puntatori funzionano in modo diverso dai numeri interi. Quando un
puntatore viene incrementato o decrementato, l'indirizzo a cui punta viene aumentato o diminuito
dalla dimensione del tipo di referente.
Ad esempio, il tipo int (alias per System.Int32 ) ha una dimensione di 4. Se un int può essere
memorizzato nell'indirizzo 0, il successivo int può essere memorizzato nell'indirizzo 4 e così via.
Nel codice:
Analogamente, il tipo long (alias per System.Int64 ) ha una dimensione di 8. Se un long può essere
memorizzato nell'indirizzo 0, il long successivo può essere memorizzato nell'indirizzo 8, e così via.
Nel codice:
Il tipo void è speciale e anche i puntatori void sono speciali e vengono utilizzati come indicatori
catch-all quando il tipo non è noto o non ha importanza. A causa della loro natura agnostica, i
puntatori di void non possono essere incrementati o decrementati:
https://riptutorial.com/it/home 729
In C e C ++, l'asterisco nella dichiarazione di una variabile puntatore fa parte dell'espressione
dichiarata. In C #, l'asterisco nella dichiarazione fa parte del tipo .
int* a;
In C e C ++, il seguente snippet dichiara un puntatore int e una variabile int . In C #, dichiara due
puntatori int :
int* a, b;
void *
void* ptr;
Qualsiasi tipo di puntatore può essere assegnato a void* utilizzando una conversione implicita:
int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;
int* p1 = (int*)IntPtr.Zero;
void* ptr = p1;
int* p2 = (int*)ptr;
C # eredita da C e C ++ l'uso del simbolo -> come mezzo per accedere ai membri di un'istanza
tramite un puntatore digitato.
struct Vector2
{
public int X;
public int Y;
}
https://riptutorial.com/it/home 730
Vector2 v;
v.X = 5;
v.Y = 10;
Console.WriteLine(x); // prints 5
Console.WriteLine(y); // prints 10
Console.WriteLine(s); // prints Vector2
Puntatori generici
I criteri che un tipo deve soddisfare per supportare i puntatori (vedere Note ) non possono essere
espressi in termini di vincoli generici. Pertanto, qualsiasi tentativo di dichiarare un puntatore a un
tipo fornito tramite un parametro di tipo generico avrà esito negativo.
https://riptutorial.com/it/home 731
Capitolo 128: Puntatori e codice non sicuro
Examples
Introduzione al codice non sicuro
C # consente di utilizzare le variabili del puntatore in una funzione del blocco di codice quando è
contrassegnato dal modificatore unsafe . Il codice non sicuro o il codice non gestito è un blocco di
codice che utilizza una variabile puntatore.
Un puntatore è 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 variabile.
type *var-name;
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 sopra riportato viene compilato ed eseguito, produce il seguente risultato:
Data is: 20
Address is: 99215364
Invece di dichiarare un intero metodo come non sicuro, è anche possibile dichiarare una parte del
https://riptutorial.com/it/home 732
codice come non sicura:
// safe code
unsafe
{
// you can use pointers here
}
// safe code
È possibile recuperare i dati memorizzati nel individuato a cui fa riferimento la variabile puntatore,
utilizzando il metodo ToString (). Il seguente esempio dimostra questo:
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 sopra riportato è stato compilato ed eseguito, produce il seguente risultato:
Data is: 20
Data is: 20
Address is: 77128984
È possibile passare una variabile puntatore a un metodo come parametro. Il seguente esempio
illustra questo:
using System;
namespace UnsafeCodeApplication
{
class TestPointer
{
public unsafe void swap(int* p, int *q)
{
int temp = *p;
https://riptutorial.com/it/home 733
*p = *q;
*q = temp;
}
In C #, un nome di matrice e un puntatore a un tipo di dati identico ai dati dell'array, non sono lo
stesso tipo di variabile. Ad esempio, int *p e int[] p , non sono dello stesso tipo. È possibile
incrementare la variabile del puntatore p perché non è fissata in memoria, ma un indirizzo di array
è fisso in memoria e non è possibile incrementarlo.
Pertanto, se è necessario accedere a dati di array utilizzando una variabile puntatore, come
facciamo tradizionalmente in C o C ++, è necessario correggere il puntatore utilizzando la parola
chiave fixed.
using System;
namespace UnsafeCodeApplication
{
class TestPointer
{
public unsafe static void Main()
{
int[] list = {10, 100, 200};
fixed(int *ptr = list)
https://riptutorial.com/it/home 734
Console.ReadKey();
}
}
}
Quando il codice sopra riportato è stato compilato ed eseguito, produce il seguente risultato:
Per la compilazione di codice non sicuro, è necessario specificare l' /unsafe riga di comando
/unsafe con il 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:
Se si utilizza IDE di Visual Studio, è necessario abilitare l'uso di codice non sicuro nelle proprietà
del progetto.
• Aprire le proprietà del progetto facendo doppio clic sul nodo delle proprietà in Esplora
soluzioni.
• Clicca sulla scheda Costruisci.
• Seleziona l'opzione "Consenti codice non sicuro"
https://riptutorial.com/it/home 735
Leggi Puntatori e codice non sicuro online: https://riptutorial.com/it/csharp/topic/5514/puntatori-e-
codice-non-sicuro
https://riptutorial.com/it/home 736
Capitolo 129: Query LINQ
introduzione
LINQ è un acronimo che sta per L anguage IN tegrated Q uery. È un concetto che integra un
linguaggio di query offrendo un modello coerente per lavorare con i dati attraverso vari tipi di fonti
e formati di dati; si utilizzano gli stessi schemi di codifica di base per interrogare e trasformare i
dati in documenti XML, database SQL, set di dati ADO.NET, raccolte .NET e qualsiasi altro
formato per il quale sia disponibile un provider LINQ.
Sintassi
• Sintassi delle query:
○ Enumerable.Aggregate (func)
○ Enumerable.Aggregate (seed, func)
○ Enumerable.Aggregate (seed, func, resultSelector)
○ Enumerable.All (predicato)
○ Enumerable.Any ()
○ Enumerable.Any (predicato)
○ Enumerable.AsEnumerable ()
○ Enumerable.Average ()
○ Enumerable.Average (selettore)
○ Enumerable.Cast <Risultato> ()
○ Enumerable.Concat (secondo)
○ Enumerable.Contains (valore)
○ Enumerable.Contains (valore, comparatore)
○ Enumerable.Count ()
○ Enumerable.Count (predicato)
○ Enumerable.DefaultIfEmpty ()
○ Enumerable.DefaultIfEmpty (defaultValue)
○ Enumerable.Distinct ()
○ Enumerable.Distinct (di confronto)
○ Enumerable.ElementAt (indice)
○ Enumerable.ElementAtOrDefault (indice)
○ Enumerable.Empty ()
○ Enumerable.Except (secondo)
○ Enumerable.Except (second, comparer)
https://riptutorial.com/it/home 737
○ Enumerable.First ()
○ Enumerable.First (predicato)
○ Enumerable.FirstOrDefault ()
○ Enumerable.FirstOrDefault (predicato)
○ Enumerable.GroupBy (keySelector)
○ Enumerable.GroupBy (keySelector, resultSelector)
○ Enumerable.GroupBy (keySelector, elementSelector)
○ Enumerable.GroupBy (keySelector, comparatore)
○ Enumerable.GroupBy (keySelector, resultSelector, comparatore)
○ Enumerable.GroupBy (keySelector, elementSelector, resultSelector)
○ Enumerable.GroupBy (keySelector, elementSelector, comparatore)
○ Enumerable.GroupBy (keySelector, elementSelector, resultSelector, comparatore)
○ Enumerable.Intersect (secondo)
○ Enumerable.Intersect (second, comparer)
○ Enumerable.Join (inner, outerKeySelector, innerKeySelector, resultSelector)
○ Enumerable.Join (inner, outerKeySelector, innerKeySelector, resultSelector,
comparatore)
○ Enumerable.Last ()
○ Enumerable.Last (predicato)
○ Enumerable.LastOrDefault ()
○ Enumerable.LastOrDefault (predicato)
○ Enumerable.LongCount ()
○ Enumerable.LongCount (predicato)
○ Enumerable.Max ()
○ Enumerable.Max (selettore)
○ Enumerable.Min ()
○ Enumerable.Min (selettore)
○ Enumerable.OfType <TResult> ()
○ Enumerable.OrderBy (keySelector)
○ Enumerable.OrderBy (keySelector, comparatore)
○ Enumerable.OrderByDescending (keySelector)
○ Enumerable.OrderByDescending (keySelector, comparatore)
○ Enumerable.Range (avvia, conta)
○ Enumerable.Repeat (element, count)
○ Enumerable.Reverse ()
○ Enumerable.Select (selettore)
○ Enumerable.SelectMany (selettore)
○ Enumerable.SelectMany (collectionSelector, resultSelector)
○ Enumerable.SequenceEqual (secondo)
○ Enumerable.SequenceEqual (secondo, comparatore)
○ Enumerable.Single ()
○ Enumerable.Single (predicato)
○ Enumerable.SingleOrDefault ()
○ Enumerable.SingleOrDefault (predicato)
○ Enumerable.Skip (conteggio)
○ Enumerable.SkipWhile (predicato)
https://riptutorial.com/it/home 738
○ Enumerable.Sum ()
○ Enumerable.Sum (selettore)
○ Enumerable.Take (conteggio)
○ Enumerable.TakeWhile (predicato)
○ orderedEnumerable.ThenBy (keySelector)
○ orderedEnumerable.ThenBy (keySelector, comparatore)
○ orderedEnumerable.ThenByDescending (keySelector)
○ orderedEnumerable.ThenByDescending (keySelector, comparatore)
○ Enumerable.ToArray ()
○ Enumerable.ToDictionary (keySelector)
○ Enumerable.ToDictionary (keySelector, elementSelector)
○ Enumerable.ToDictionary (keySelector, comparatore)
○ Enumerable.ToDictionary (keySelector, elementSelector, comparatore)
○ Enumerable.ToList ()
○ Enumerable.ToLookup (keySelector)
○ Enumerable.ToLookup (keySelector, elementSelector)
○ Enumerable.ToLookup (keySelector, comparatore)
○ Enumerable.ToLookup (keySelector, elementSelector, comparatore)
○ Enumerable.Union (secondo)
○ Enumerable.Union (second, comparer)
○ Enumerable.Where (predicato)
○ Enumerable.Zip (second, resultSelector)
Osservazioni
Per utilizzare le query LINQ è necessario importare System.Linq .
La sintassi del metodo è più potente e flessibile, ma la sintassi delle query potrebbe essere più
semplice e più familiare. Tutte le query scritte nella sintassi Query sono tradotte nella sintassi
funzionale dal compilatore, quindi le prestazioni sono le stesse.
Gli oggetti di query non vengono valutati fino a quando non vengono utilizzati, in modo che
possano essere modificati o aggiunti senza penalizzare le prestazioni.
Examples
Dove
List<string> trees = new List<string>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };
https://riptutorial.com/it/home 739
var shortTrees = trees.Where(tree => tree.Length == 3); // Oak, Elm
Select consente di applicare una trasformazione a ogni elemento in qualsiasi struttura dati che
implementa IEnumerable.
List<String> trees = new List<String>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };
//The below select stament transforms each element in tree into its first character.
IEnumerable<String> initials = trees.Select(tree => tree.Substring(0, 1));
foreach (String initial in initials) {
System.Console.WriteLine(initial);
}
Produzione:
O
B
B
E
H
M
Metodi di concatenamento
https://riptutorial.com/it/home 740
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector
)
Mentre alcuni metodi di concatenamento possono richiedere l' esecuzione di un intero set prima di
andare avanti, LINQ sfrutta l' esecuzione differita usando MSDN return return che crea un
Enumerable e un Enumerator dietro le quinte. Il processo di concatenamento in LINQ consiste
essenzialmente nella costruzione di un enumerabile (iteratore) per il set originale - che viene
rinviato - fino a quando non si materializza enumerando l'enumerabile .
Ciò consente a queste funzioni di essere fluentemente collegate a wiki , in cui una funzione può
agire direttamente sul risultato di un'altra. Questo stile di codice può essere utilizzato per eseguire
molte operazioni basate su sequenze in una singola istruzione.
Ad esempio, è possibile combinare Select , Where e OrderBy per trasformare, filtrare e ordinare una
sequenza in una singola istruzione.
var someNumbers = { 4, 3, 2, 1 };
Produzione:
2
4
8
Qualsiasi funzione che estenda e restituisca il tipo IEnumerable<T> generico può essere utilizzata
come clausole concatenate in una singola istruzione. Questo stile di programmazione fluida è
potente e dovrebbe essere preso in considerazione quando si creano i propri metodi di estensione
.
Intervallo e ripetizione
I metodi statici Range e Repeat su Enumerable possono essere utilizzati per generare sequenze
semplici.
https://riptutorial.com/it/home 741
Gamma
Enumerable.Range() genera una sequenza di numeri interi dati un valore iniziale e un conteggio.
// Generate a collection containing the numbers 1-100 ([1, 2, 3, ..., 98, 99, 100])
var range = Enumerable.Range(1,100);
Ripetere
Enumerable.Repeat() genera una sequenza di elementi ripetuti in base a un elemento e al numero
di ripetizioni richieste.
Salta e prendi
Il metodo Skip restituisce una collezione escludendo un numero di elementi dall'inizio della
raccolta di origine. Il numero di articoli esclusi è il numero dato come argomento. Se nella raccolta
sono presenti meno elementi di quelli specificati nell'argomento, viene restituita una raccolta
vuota.
Il metodo Take restituisce una raccolta contenente un numero di elementi dall'inizio della raccolta
di origine. Il numero di elementi inclusi è il numero indicato come argomento. Se nella raccolta
sono presenti meno elementi di quelli specificati nell'argomento, la raccolta restituita conterrà gli
stessi elementi della raccolta di origine.
Skip and Take sono comunemente usati insieme per impaginare i risultati, ad esempio:
Avviso: LINQ to Entities supporta solo Salta sulle query ordinate . Se si tenta di
https://riptutorial.com/it/home 742
utilizzare Skip senza ordinare, verrà visualizzato NotSupportedException con il
messaggio "Il metodo 'Skip' è supportato solo per l'input ordinato in LINQ alle entità. Il
metodo 'OrderBy' deve essere chiamato prima del metodo 'Salta'."
Tutti e sei i metodi restituiscono un singolo valore del tipo di sequenza e possono essere chiamati
con o senza un predicato.
A seconda del numero di elementi che corrispondono al predicate o, se non viene fornito alcun
predicate , il numero di elementi nella sequenza sorgente, si comportano come segue:
Primo()
• Restituisce il primo elemento di una sequenza o il primo elemento che corrisponde al
predicate fornito.
• Se la sequenza non contiene elementi, viene generata una InvalidOperationException con il
messaggio: "Sequenza non contiene elementi".
• Se la sequenza non contiene elementi corrispondenti al predicate fornito, viene generata una
InvalidOperationException con il messaggio "Sequenza non contiene alcun elemento
corrispondente".
Esempio
// Returns "a":
new[] { "a" }.First();
// Returns "a":
new[] { "a", "b" }.First();
// Returns "b":
new[] { "a", "b" }.First(x => x.Equals("b"));
// Returns "ba":
new[] { "ba", "be" }.First(x => x.Contains("b"));
// Throws InvalidOperationException:
new[] { "ca", "ce" }.First(x => x.Contains("b"));
// Throws InvalidOperationException:
new string[0].First();
FirstOrDefault ()
• Restituisce il primo elemento di una sequenza o il primo elemento che corrisponde al
predicate fornito.
• Se la sequenza non contiene elementi o nessun elemento che corrisponde al predicate
https://riptutorial.com/it/home 743
fornito, restituisce il valore predefinito del tipo di sequenza usando il default(T) .
Esempio
// Returns "a":
new[] { "a" }.FirstOrDefault();
// Returns "a":
new[] { "a", "b" }.FirstOrDefault();
// Returns "b":
new[] { "a", "b" }.FirstOrDefault(x => x.Equals("b"));
// Returns "ba":
new[] { "ba", "be" }.FirstOrDefault(x => x.Contains("b"));
// Returns null:
new[] { "ca", "ce" }.FirstOrDefault(x => x.Contains("b"));
// Returns null:
new string[0].FirstOrDefault();
Scorso()
• Restituisce l'ultimo elemento di una sequenza o l'ultimo elemento che corrisponde al
predicate fornito.
• Se la sequenza non contiene elementi, viene lanciata una InvalidOperationException con il
messaggio "Sequenza non contiene elementi".
• Se la sequenza non contiene elementi corrispondenti al predicate fornito, viene generata una
InvalidOperationException con il messaggio "Sequenza non contiene alcun elemento
corrispondente".
Esempio
// Returns "a":
new[] { "a" }.Last();
// Returns "b":
new[] { "a", "b" }.Last();
// Returns "a":
new[] { "a", "b" }.Last(x => x.Equals("a"));
// Returns "be":
new[] { "ba", "be" }.Last(x => x.Contains("b"));
// Throws InvalidOperationException:
new[] { "ca", "ce" }.Last(x => x.Contains("b"));
// Throws InvalidOperationException:
new string[0].Last();
https://riptutorial.com/it/home 744
LastOrDefault ()
• Restituisce l'ultimo elemento di una sequenza o l'ultimo elemento che corrisponde al
predicate fornito.
• Se la sequenza non contiene elementi o nessun elemento che corrisponde al predicate
fornito, restituisce il valore predefinito del tipo di sequenza usando il default(T) .
Esempio
// Returns "a":
new[] { "a" }.LastOrDefault();
// Returns "b":
new[] { "a", "b" }.LastOrDefault();
// Returns "a":
new[] { "a", "b" }.LastOrDefault(x => x.Equals("a"));
// Returns "be":
new[] { "ba", "be" }.LastOrDefault(x => x.Contains("b"));
// Returns null:
new[] { "ca", "ce" }.LastOrDefault(x => x.Contains("b"));
// Returns null:
new string[0].LastOrDefault();
Singolo ()
• Se la sequenza contiene esattamente un elemento, o esattamente un elemento che
corrisponde al predicate fornito, tale elemento viene restituito.
• Se la sequenza non contiene elementi o nessun elemento corrispondente al predicate
fornito, viene generata una InvalidOperationException con il messaggio "Sequenza non
contiene elementi".
• Se la sequenza contiene più di un elemento o più di un elemento che corrisponde al
predicate fornito, viene generata una InvalidOperationException con il messaggio "Sequenza
contiene più di un elemento".
• Nota: per valutare se la sequenza contiene esattamente un elemento, al massimo due
elementi devono essere enumerati.
Esempio
// Returns "a":
new[] { "a" }.Single();
// Returns "b":
new[] { "a", "b" }.Single(x => x.Equals("b"));
https://riptutorial.com/it/home 745
// Throws InvalidOperationException:
new[] { "a", "b" }.Single(x => x.Equals("c"));
// Throws InvalidOperationException:
new string[0].Single();
SingleOrDefault ()
• Se la sequenza contiene esattamente un elemento, o esattamente un elemento che
corrisponde al predicate fornito, tale elemento viene restituito.
• Se la sequenza non contiene elementi o nessun elemento corrispondente al predicate
fornito, viene restituito il default(T) .
• Se la sequenza contiene più di un elemento o più di un elemento che corrisponde al
predicate fornito, viene generata una InvalidOperationException con il messaggio "Sequenza
contiene più di un elemento".
• Se la sequenza non contiene elementi corrispondenti al predicate fornito, restituisce il valore
predefinito del tipo di sequenza usando il default(T) .
• Nota: per valutare se la sequenza contiene esattamente un elemento, al massimo due
elementi devono essere enumerati.
Esempio
// Returns "a":
new[] { "a" }.SingleOrDefault();
// returns "a"
new[] { "a", "b" }.SingleOrDefault(x => x == "a");
// Returns null:
new[] { "a", "b" }.SingleOrDefault(x => x == "c");
// Throws InvalidOperationException:
new[] { "a", "a" }.SingleOrDefault(x => x == "a");
// Throws InvalidOperationException:
new[] { "a", "b" }.SingleOrDefault();
// Returns null:
new string[0].SingleOrDefault();
raccomandazioni
• Sebbene sia possibile utilizzare FirstOrDefault , LastOrDefault o SingleOrDefault per
verificare se una sequenza contiene elementi, Any o Count sono più affidabili. Questo perché
un valore di ritorno di default(T) da uno di questi tre metodi non dimostra che la sequenza
sia vuota, poiché il valore del primo / ultimo / singolo elemento della sequenza potrebbe
https://riptutorial.com/it/home 746
essere ugualmente default(T)
• Decidi quali metodi si adattano di più al tuo codice. Ad esempio, usa Single solo se devi
assicurarti che ci sia un singolo oggetto nella collezione che corrisponde al tuo predicato,
altrimenti usa First ; come Single lancia un'eccezione se la sequenza ha più di un elemento
corrispondente. Questo ovviamente vale anche per le controparti "* OrDefault".
• Riguardo all'efficienza: sebbene sia spesso opportuno assicurarsi che vi sia un solo
elemento ( Single ) o, o solo uno o zero ( SingleOrDefault ), restituiti da una query, entrambi
questi metodi richiedono più, e spesso l'intero, della raccolta da esaminare per assicurarsi
che non ci sia una seconda corrispondenza alla domanda. Questo è diverso dal
comportamento di, ad esempio, il First metodo, che può essere soddisfatto dopo aver
trovato la prima corrispondenza.
tranne
Il metodo Except restituisce l'insieme di elementi contenuti nella prima raccolta ma non contenuti
nella seconda. Il valore predefinito di IEqualityComparer viene utilizzato per confrontare gli elementi
all'interno dei due set. C'è un sovraccarico che accetta un IEqualityComparer come argomento.
Esempio:
int[] first = { 1, 2, 3, 4 };
int[] second = { 0, 2, 3, 5 };
Produzione:
1
4
In questo caso. .Except(second) esclude gli elementi contenuti nell'array second , ovvero 2 e 3 (0 e
5 non sono contenuti nel first array e vengono saltati).
Nota che Except implica Distinct (cioè rimuove gli elementi ripetuti). Per esempio:
int[] third = { 1, 1, 1, 2, 3, 4 };
Produzione:
1
4
https://riptutorial.com/it/home 747
Live Demo su .NET Fiddle
holidayDifference = remoteHolidays
.Except(localHolidays)
.ToList();
Produzione:
https://riptutorial.com/it/home 748
Hanukkah
https://riptutorial.com/it/home 749
Content = "Cool post!"
}
}
},
new BlogPost()
{
Id = 2,
Comments = new List<Comment>()
{
new Comment()
{
Id = 3,
Content = "I don't think you're right",
},
new Comment()
{
Id = 4,
Content = "This post is a complete nonsense"
}
}
}
};
Ora vogliamo selezionare i commenti Content con Id di BlogPost associata a questo commento. Per
fare ciò, possiamo usare il sovraccarico SelectMany appropriato.
var commentsWithIds = posts.SelectMany(p => p.Comments, (post, comment) => new { PostId =
post.Id, CommentContent = comment.Content });
{
PostId = 1,
CommentContent = "It's really great!"
},
{
PostId = 1,
CommentContent = "Cool post!"
},
{
PostId = 2,
CommentContent = "I don't think you're right"
},
{
PostId = 2,
CommentContent = "This post is a complete nonsense"
}
SelectMany
https://riptutorial.com/it/home 750
var splitAndCombine = words.SelectMany(x => x.Split(','));
// returns { "a", "b", "c", "d", "e", "f" }
Se si utilizza una funzione di selezione che trasforma gli elementi di input in sequenze, il risultato
saranno gli elementi di tali sequenze restituite una alla volta.
class School
{
public Student[] Students { get; set; }
}
class Student
{
public string Name { get; set; }
}
Produzione:
peso
Jack
Jim
John
Tutti
Allè usato per controllare, se tutti gli elementi di una collezione corrispondono a una condizione o
meno.
vedi anche:. Any
1. Parametro vuoto
Tutto : non è consentito l'uso con parametro vuoto.
https://riptutorial.com/it/home 751
2. Espressione lambda come parametro
Tutto : restituisce true se tutti gli elementi della raccolta soddisfano l'espressione lambda e false
altrimenti:
3. Raccolta vuota
Tutto : restituisce true se la raccolta è vuota e viene fornita un'espressione lambda:
Nota: All interromperanno l'iterazione della raccolta non appena trova un elemento che non
corrisponde alla condizione. Ciò significa che la raccolta non sarà necessariamente
completamente elencata; sarà elencato solo abbastanza lontano da trovare il primo elemento che
non corrisponde alla condizione.
interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }
Utilizzando OfType
Usando Where
var foos = collection.Where(item => item is Foo); // result: IEnumerable<IFoo> with item0 and
item1
var bars = collection.Where(item => item is Bar); // result: IEnumerable<IFoo> with item2 and
item3
Utilizzando Cast
https://riptutorial.com/it/home 752
var bars = collection.Cast<Bar>(); // throws InvalidCastException on the 1st
item
var foos = collection.Cast<Foo>(); // throws InvalidCastException on the 3rd
item
var foosAndBars = collection.Cast<IFoo>(); // OK
Unione
Unisce due raccolte per creare una raccolta distinta utilizzando il comparatore di uguaglianza
predefinito
int[] numbers1 = { 1, 2, 3 };
int[] numbers2 = { 2, 3, 4, 5 };
SI UNISCE
I join vengono utilizzati per combinare diversi elenchi o tabelle contenenti i dati tramite una chiave
comune.
(Interno) Unisciti
// Result: {"a","a"}
// {"c","c"}
https://riptutorial.com/it/home 753
select new { First = f, Second = t};
// Result: {"a","a"}
// {"b", null}
// {"c","c"}
// Result: {"a","a"}
// {"c","c"}
// {null,"d"}
Cross Join
var CrossJoin = from f in first
from s in second
select new { f, s };
// Result: {"a","a"}
// {"a","c"}
// {"a","d"}
// {"b","a"}
// {"b","c"}
// {"b","d"}
// {"c","a"}
// {"c","c"}
// {"c","d"}
// Result: {"a","a"}
// {"b", null}
// {"c","c"}
https://riptutorial.com/it/home 754
// {null,"d"}
Esempio pratico
Gli esempi sopra hanno una struttura dati semplice in modo che tu possa concentrarti sulla
comprensione dei diversi LINQ che si uniscono tecnicamente, ma nel mondo reale avresti tabelle
con colonne a cui devi unirti.
Nell'esempio seguente, vi è una sola Region classe utilizzata, in realtà si unirebbero due o più
tabelle diverse che contengono la stessa chiave (in questo esempio, il first e il second vengono
uniti tramite l' ID chiave comune).
// Left data
var first = new List<Region>()
{ new Region(1), new Region(3), new Region(4) };
// Right data
var second = new List<Region>()
{
new Region(1, "Eastern"), new Region(2, "Western"),
new Region(3, "Northern"), new Region(4, "Southern")
};
Puoi vedere che in questo esempio first non contiene alcuna descrizione di regione, quindi vuoi
unirti a loro dal second . Quindi l'unione interna sarebbe simile a:
// Result: {1,"Eastern"}
// {3, Northern}
// {4,"Southern"}
Questo risultato ha creato oggetti anonimi al volo, il che va bene, ma abbiamo già creato una
classe appropriata, quindi possiamo specificarla: invece di select new { f.ID, s.RegionDescription
};
https://riptutorial.com/it/home 755
possiamo dire select new Region(f.ID, s.RegionDescription); , che restituirà gli stessi dati ma
creerà oggetti di tipo Region , che manterranno la compatibilità con gli altri oggetti.
distinto
int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };
Per confrontare un tipo di dati personalizzato, è necessario implementare l' IEquatable<T> e fornire
i metodi GetHashCode ed Equals per il tipo. Oppure il comparatore di uguaglianza può essere
sovrascritto:
List<Person> people;
distinct = people.Distinct(SSNEqualityComparer);
foreach (var grp in films.GroupBy(f => new { Category = f.Category, Year = f.Year })) {
var groupCategory = grp.Key.Category;
var groupYear = grp.Key.Year;
var numberOfFilmsInCategory = grp.Count();
}
https://riptutorial.com/it/home 756
Utilizzo di Range con vari metodi Linq
È possibile utilizzare la classe Enumerable insieme alle query Linq per convertire i loop in Linq
one liners.
Seleziona Esempio
Opposto a questo:
Puoi farlo:
Dove esempio
In questo esempio, verranno generati 100 numeri e anche quelli verranno estratti
Ascendente:
var sortedNames =
from name in names
orderby name
select name;
Discendente:
https://riptutorial.com/it/home 757
var sortedNames =
from name in names
orderby name descending
select name;
Person[] people =
{
new Person { FirstName = "Steve", LastName = "Collins", Age = 30},
new Person { FirstName = "Phil" , LastName = "Collins", Age = 28},
new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 29},
new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 15}
};
Risultato
1. Adam Ackerman 29
2. Adam Ackerman 15
3. Phil Collins 28
4. Steve Collins 30
Nozioni di base
https://riptutorial.com/it/home 758
new Student { Name = "Joe", Grade = 59, HasSnack = false }
}
Possiamo "interrogare" su questi dati usando la sintassi LINQ. Ad esempio, per recuperare tutti gli
studenti che hanno uno spuntino oggi:
Oppure, per recuperare studenti con un punteggio pari o superiore a 90, e restituire solo i loro
nomi, non l'oggetto Student completo:
La funzione LINQ è composta da due sintassi che svolgono le stesse funzioni, hanno prestazioni
quasi identiche, ma sono scritte in modo molto diverso. La sintassi dell'esempio precedente è
chiamata sintassi della query . L'esempio seguente, tuttavia, illustra la sintassi del metodo . Gli
stessi dati verranno restituiti come nell'esempio sopra, ma il modo in cui la query è scritta è
diverso.
Raggruppa per
GroupBy è un modo semplice per ordinare una raccolta di oggetti IEnumerable<T> in gruppi distinti.
Semplice esempio
In questo primo esempio, ci ritroviamo con due gruppi, elementi pari e dispari.
https://riptutorial.com/it/home 759
Prendiamo come esempio un elenco di persone per età. Per prima cosa creeremo un oggetto
Persona che ha due proprietà, Nome ed Età.
Quindi creiamo la nostra lista di esempi di persone con vari nomi ed età.
Quindi creiamo una query LINQ per raggruppare il nostro elenco di persone per età.
In questo modo, possiamo vedere l'età per ogni gruppo e avere un elenco di ogni persona nel
gruppo.
20
Mouse
30
Neo
Trinity
40
Morpheus
Dozer
Smith
Qualunque
Anyviene usato per verificare se qualche elemento di una collezione corrisponde a una
condizione o meno.
https://riptutorial.com/it/home 760
vedi anche: .Tutte , ne e FirstOrDefault: best practice
1. Parametro vuoto
Qualsiasi : restituisce true se la raccolta ha elementi e false se la raccolta è vuota:
3. Raccolta vuota
Qualsiasi : restituisce false se la raccolta è vuota e viene fornita un'espressione lambda:
Nota: Any interromperà l'iterazione della raccolta non appena trova un elemento corrispondente
alla condizione. Ciò significa che la raccolta non sarà necessariamente completamente elencata;
verrà elencato solo quanto basta per trovare il primo elemento corrispondente alla condizione.
ToDictionary
Il metodo LINQ ToDictionary() può essere utilizzato per generare un insieme di Dictionary<TKey,
TElement> basato su una sorgente I Dictionary<TKey, TElement> IEnumerable<T> .
In questo esempio, il singolo argomento passato a ToDictionary è di tipo Func<TSource, TKey> , che
restituisce la chiave per ciascun elemento.
https://riptutorial.com/it/home 761
Dictionary<int, User> usersById = new Dictionary<int User>();
foreach (User u in users)
{
usersById.Add(u.Id, u);
}
È anche possibile specificare IComparer che viene utilizzato per confrontare i valori chiave. Questo
può essere utile quando la chiave è una stringa e vuoi che corrisponda a maiuscole e minuscole.
Nota: il metodo ToDictionary richiede che tutte le chiavi siano univoche, non ci devono essere
chiavi duplicate. Se ci sono, allora viene generata un'eccezione: ArgumentException: An item with
the same key has already been added. Se hai uno scenario in cui sai che avrai più elementi con la
stessa chiave, allora preferisci utilizzare ToLookup .
Aggregato
int[] intList = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = intList.Aggregate((prevSum, current) => prevSum + current);
// sum = 55
Un secondo overload di Aggregate riceve anche un parametro seed che è il valore dell'accumulatore
iniziale. Questo può essere usato per calcolare più condizioni su una collezione senza iterarlo più
di una volta.
https://riptutorial.com/it/home 762
Per la raccolta di items che vogliamo calcolare
1. Il totale .Count
2. La quantità di numeri pari
3. Colleziona ogni singolo oggetto
Si noti che l'utilizzo di un tipo anonimo come seed deve istanziare un nuovo oggetto ogni
elemento perché le proprietà sono di sola lettura. Usando una classe personalizzata si può
semplicemente assegnare l'informazione e non è necessario alcun new (solo quando si fornisce il
parametro iniziale del seed
Per definire una variabile all'interno di un'espressione linq, è possibile utilizzare la parola chiave
let . Questo di solito è fatto per archiviare i risultati di sottoquery intermedie, ad esempio:
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Produzione:
https://riptutorial.com/it/home 763
Il risultato della query include il numero 6 con il quadrato di 36.
Il risultato della query include il numero 7 con il quadrato di 49.
Il risultato della query include il numero 8 con un quadrato di 64.
Il risultato della query include il numero 9 con il quadrato di 81.
Visualizza la demo
SkipWhile
SkipWhile()viene utilizzato per escludere elementi fino alla prima non corrispondenza (questo
potrebbe essere controintuitivo per la maggior parte)
DefaultIfEmpty
DefaultIfEmpty viene utilizzato per restituire un elemento predefinito se la sequenza non contiene
elementi. Questo elemento può essere il valore predefinito del tipo o un'istanza definita dall'utente
di quel tipo. Esempio:
https://riptutorial.com/it/home 764
Console.WriteLine("Num = {0} ** Char = {1}", item.Number, item.Character);
}
ouput:
Num = 99 Char = c
Num = 100 Char = d
Num = 5 Char = ?
Num = 20 Char = ?
Num = 102 Char = ?
Num = 105 Char = i
Nel caso in cui venga utilizzato un DefaultIfEmpty (senza specificare un valore predefinito) e ciò
comporterà l'assenza di elementi corrispondenti nella sequenza corretta, è necessario assicurarsi
che l'oggetto non sia null prima di accedere alle sue proprietà. Altrimenti risulterà in una
NullReferenceException . Esempio:
SequenceEqual
SequenceEqual viene utilizzato per confrontare due sequenze I IEnumerable<T> Enumerabili l'una con
l'altra.
Count e LongCount
https://riptutorial.com/it/home 765
Countrestituisce il numero di elementi in un oggetto IEnumerable<T> . Count espone anche un
parametro di predicato opzionale che consente di filtrare gli elementi che si desidera contare.
int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };
LongCountfunziona allo stesso modo di Count ma ha un tipo restituito di long e viene utilizzato per il
conteggio IEnumerable<T> sequenze IEnumerable<T> che sono più lunghe di int.MaxValue
Poiché LINQ utilizza l' esecuzione posticipata , possiamo avere un oggetto query che in realtà
non contiene i valori, ma restituirà i valori quando valutato. Possiamo quindi creare dinamicamente
la query in base al nostro flusso di controllo e valutarla una volta che abbiamo finito:
if (!search.Years.Contains("all", StringComparer.OrdinalIgnoreCase))
query = query.Where(v => search.Years.Contains(v.Year));
if (!search.Makes.Contains("all", StringComparer.OrdinalIgnoreCase)) {
query = query.Where(v => search.Makes.Contains(v.Make));
}
if (!search.Models.Contains("all", StringComparer.OrdinalIgnoreCase)) {
query = query.Where(v => search.Models.Contains(v.Model));
}
if (!search.Cylinders.Equals("all", StringComparer.OrdinalIgnoreCase)) {
decimal minCylinders = 0;
decimal maxCylinders = 0;
switch (search.Cylinders) {
case "2-4":
https://riptutorial.com/it/home 766
maxCylinders = 4;
break;
case "5-6":
minCylinders = 5;
maxCylinders = 6;
break;
case "8":
minCylinders = 8;
maxCylinders = 8;
break;
case "10+":
minCylinders = 10;
break;
}
if (minCylinders > 0) {
query = query.Where(v => v.Cylinders >= minCylinders);
}
if (maxCylinders > 0) {
query = query.Where(v => v.Cylinders <= maxCylinders);
}
}
switch (search.SortingColumn.ToLower()) {
case "make_model":
query = query.OrderBy(v => v.Make).ThenBy(v => v.Model);
break;
case "year":
query = query.OrderBy(v => v.Year);
break;
case "engine_size":
query = query.OrderBy(v => v.EngineSize).ThenBy(v => v.Cylinders);
break;
default:
query = query.OrderBy(v => v.Year); //The default sorting.
}
Una volta ottenuto l'oggetto query, possiamo valutare i risultati con un ciclo foreach o uno dei
metodi LINQ che restituisce un insieme di valori, come ToList o ToArray :
SearchModel sm;
https://riptutorial.com/it/home 767
// populate the search model here
// ...
Cerniera lampo
Il metodo di estensione Zip agisce su due raccolte. Associa ogni elemento delle due serie in base
alla posizione. Con un'istanza di Func , utilizziamo Zip per gestire gli elementi delle due raccolte C
# in coppie. Se le serie differiscono per dimensioni, gli elementi extra delle serie più grandi
verranno ignorati.
int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip(words, (n, w) => n + "=" + w);
Produzione:
3 = tre
5 = cinque
7 = sette
Visualizza la demo
var groupJoinQuery =
from c in customers
join p in purchases on c.ID equals p.CustomerID
into custPurchases
select new
{
CustName = c.Name,
custPurchases
};
ElementAt e ElementAtOrDefault
int[] numbers = { 1, 2, 3, 4, 5 };
numbers.ElementAt(2); // 3
numbers.ElementAt(10); // throws ArgumentOutOfRangeException
https://riptutorial.com/it/home 768
enumerabile, restituisce un default(T) .
int[] numbers = { 1, 2, 3, 4, 5 };
numbers.ElementAtOrDefault(2); // 3
numbers.ElementAtOrDefault(10); // 0 = default(int)
Sia ElementAt che ElementAtOrDefault sono ottimizzati per quando la sorgente è un IList<T> e in
questi casi verrà utilizzata l'indicizzazione normale.
Si noti che per ElementAt , se l'indice fornito è maggiore della dimensione del IList<T> , l'elenco
dovrebbe (ma tecnicamente non è garantito) generare una ArgumentOutOfRangeException .
Quantificatori di Linq
Le operazioni Quantifier restituiscono un valore booleano se alcuni o tutti gli elementi di una
sequenza soddisfano una condizione. In questo articolo vedremo alcuni comuni scenari LINQ su
oggetti in cui possiamo utilizzare questi operatori. Esistono 3 operazioni Quantifiers che possono
essere utilizzate in LINQ:
All- utilizzato per determinare se tutti gli elementi di una sequenza soddisfano una condizione.
Per esempio:
Any: utilizzato per determinare se alcuni elementi di una sequenza soddisfano una condizione. Per
esempio:
//for a string
var stringValue="hello";
https://riptutorial.com/it/home 769
stringValue.Contains("h");
new Customer() {
Id = Guid.NewGuid().ToString(),
Name = "Customer2"
}
};
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[0].Id,
Description = "Customer1-Purchase2"
},
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[1].Id,
https://riptutorial.com/it/home 770
Description = "Customer2-Purchase1"
},
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[1].Id,
Description = "Customer2-Purchase2"
}
};
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[1].Id,
Detail = "Purchase2-PurchaseItem1"
},
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[1].Id,
Detail = "Purchase2-PurchaseItem2"
},
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[3].Id,
Detail = "Purchase3-PurchaseItem1"
}
};
https://riptutorial.com/it/home 771
Customer1, Customer1-Purchase2, Purchase2-PurchaseItem1
var query =
from s in stringProps
join b in builderProps
on new { s.Name, s.PropertyType } equals new { b.Name, b.PropertyType }
select new
{
s.Name,
s.PropertyType,
StringToken = s.MetadataToken,
StringBuilderToken = b.MetadataToken
};
Si noti che i tipi anonimi in join sopra devono contenere le stesse proprietà poiché gli oggetti sono
considerati uguali solo se tutte le loro proprietà sono uguali. Altrimenti la query non verrà
compilata.
Seleziona con Func selettore - Utilizzare per ottenere il ranking degli elementi
Sui sovraccarichi dei metodi di estensione Select passa anche l' index dell'elemento corrente nella
raccolta select . Questi sono alcuni usi di esso.
https://riptutorial.com/it/home 772
Ottieni la classifica dei gruppi (noto anche in Oracle come dense_rank)
E i dati:
TakeWhile
Somma
https://riptutorial.com/it/home 773
Nel caso in cui gli elementi della raccolta siano essi stessi numeri, è possibile calcolare la somma
direttamente.
Nel caso in cui il tipo degli elementi sia di tipo complesso, è possibile utilizzare un'espressione
lambda per specificare il valore da calcolare:
• Int32
• Int64
• singolo
• Doppio
• Decimale
Nel caso in cui la tua raccolta contenga tipi annullabili, puoi utilizzare l'operatore null-coalescing
per impostare un valore predefinito per elementi null:
ToLookup
Un altro esempio:
https://riptutorial.com/it/home 774
//print odd numbers after joining
Console.WriteLine(string.Join(",",lookup[1]));
//output: 1,3,5,7
Una delle grandi cose di Linq è che è così facile da estendere. Hai solo bisogno di creare un
metodo di estensione il cui argomento è IEnumerable<T> .
Questo esempio suddivide gli elementi in un oggetto IEnumerable<T> in elenchi di dimensioni fisse,
l'ultimo elenco contenente il resto degli elementi. Si noti come l'oggetto a cui viene applicato il
metodo di estensione viene passato in (argomento source ) come argomento iniziale utilizzando la
parola chiave this . Quindi la parola chiave yield viene utilizzata per generare l'elemento
successivo nell'output IEnumerable<T> prima di continuare con l'esecuzione da quel punto (vedere
la parola chiave yield ).
//using MyNamespace;
var items = new List<int> { 2, 3, 4, 5, 6 };
foreach (List<int> sublist in items.Batch(3))
{
// do something
}
I metodi LinQ personalizzati possono anche essere combinati con i metodi LinQ standard. per
esempio:
//using MyNamespace;
https://riptutorial.com/it/home 775
var result = Enumerable.Range(0, 13) // generate a list
.Where(x => x%2 == 0) // filter the list or do something other
.Batch(3) // call our extension method
.ToList() // call other standard methods
Questa query restituirà numeri pari raggruppati in batch con una dimensione di 3: {0, 2, 4}, {6,
8, 10}, {12}
Ricorda che hai bisogno di using MyNamespace; linea per poter accedere al metodo di estensione.
Dato 2 elenchi
Non spiegherò cosa fa Any e FirstOrDefault perché ci sono già due buoni esempi su di loro.
Vedere Any and First, FirstOrDefault, Last, LastOrDefault, Single e SingleOrDefault per ulteriori
informazioni.
Un modello che vedo spesso nel codice che dovrebbe essere evitato è
if (myEnumerable.Any(t=>t.Foo == "Bob"))
{
var myFoo = myEnumerable.First(t=>t.Foo == "Bob");
//Do stuff
}
Utilizzando il secondo esempio, la raccolta viene ricercata una sola volta e restituisce lo stesso
https://riptutorial.com/it/home 776
risultato della prima. La stessa idea può essere applicata a Single .
https://riptutorial.com/it/home 777
}).ToList();
Inverso
Esempio:
// Create an array.
int[] array = { 1, 2, 3, 4 }; //Output:
// Call reverse extension method on the array. //4
var reverse = array.Reverse(); //3
// Write contents of array to screen. //2
foreach (int value in reverse) //1
Console.WriteLine(value);
Ricorda che Reverse() può funzionare in modo diverso a seconda dell'ordine della catena delle
istruzioni LINQ.
//reverseFirst output: 6, 5
//reverseLast output: 2, 1
Reverse () funziona con il buffering di tutto quindi lo attraversa all'indietro, non è molto efficiente,
ma nemmeno OrderBy da quella prospettiva.
https://riptutorial.com/it/home 778
In LINQ-to-Objects, ci sono operazioni di buffering (Reverse, OrderBy, GroupBy, ecc.) E
operazioni di non buffering (Where, Take, Skip, ecc.).
Enumerazione dell'enumerabile
L'interfaccia IEnumerable <T> è l'interfaccia di base per tutti gli enumeratori generici ed è una
parte essenziale per la comprensione di LINQ. Nel suo nucleo, rappresenta la sequenza.
Questa interfaccia sottostante è ereditata da tutte le raccolte generiche, come Collection <T> ,
Array , List <T> , Dictionary <TKey, TValue> Class e HashSet <T> .
Oltre a rappresentare la sequenza, qualsiasi classe che eredita da IEnumerable <T> deve fornire
un IEnumerator <T>. L'enumeratore espone l'iteratore per l'enumerabile, e queste due interfacce e
idee interconnesse sono la fonte del detto "enumerare l'enumerabile".
Solo una volta che l'enumerabile è stato enumerato, ciò provoca la materializzazione degli oggetti,
ovvero quando le metriche come la complessità temporale (quanto tempo occorre prendere in
relazione alle dimensioni della serie) e la complessità spaziale (quanto spazio dovrebbe usare in
relazione alle dimensioni della serie) possono essere misurato
La creazione della propria classe che eredita da IEnumerable <T> può essere un po 'complicata a
seconda delle serie sottostanti che devono essere enumerabili. In generale, è meglio utilizzare
una delle raccolte generiche esistenti. Detto questo, è anche possibile ereditare dall'interfaccia
IEnumerable <T> senza avere una matrice definita come struttura sottostante.
Ad esempio, utilizzando la serie di Fibonacci come sequenza sottostante. Si noti che la chiamata
a Where semplicemente costruisce un oggetto IEnumerable , e non è fino a quando una chiamata
per enumerare quella enumerabile è fatta che tutti i valori sono materializzati.
void Main()
https://riptutorial.com/it/home 779
{
Fibonacci Fibo = new Fibonacci();
IEnumerable<long> quadrillionplus = Fibo.Where(i => i > 1000000000000);
Console.WriteLine("Enumerable built");
Console.WriteLine(quadrillionplus.Take(2).Sum());
Console.WriteLine(quadrillionplus.Skip(2).First());
Produzione
Enumerable built
Enumerating the Enumerable
4052739537881
Enumerating the Enumerable
4052739537881
Enumerable built
Enumerating the Enumerable
14930352
La forza nel secondo set (il fibMod612) è che anche se abbiamo fatto la chiamata per ordinare
l'intero set di numeri di Fibonacci, poiché è stato preso solo un valore usando .First() la
complessità temporale era O (n) come solo 1 valore doveva essere confrontato durante
l'esecuzione dell'algoritmo di ordinazione. Questo perché il nostro enumeratore ha chiesto solo 1
valore, e quindi non è stato necessario materializzare l'intero enumerabile. Se avessimo usato
.Take(5) anziché .First() l'enumeratore avrebbe richiesto 5 valori e al massimo 5 valori avrebbero
https://riptutorial.com/it/home 780
dovuto essere materializzati. Rispetto alla necessità di ordinare un intero set e quindi prendere i
primi 5 valori, il principio di risparmiare un sacco di tempo e spazio di esecuzione.
Ordinato da
Quando il valore è un numero intero , doppio o float inizia con il valore minimo , il che significa
che si ottengono prima i valori negativi, che zero e afterwords i valori positivi (vedere Esempio 1).
Quando ordini per char, il metodo confronta i valori ascii dei caratteri per ordinare la raccolta (vedi
Esempio 2).
Questo tipo di ordine è chiamato ascendente, se lo vuoi viceversa hai bisogno di scendere (vedi
OrderByDescending).
Esempio 1:
Esempio 2:
char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z',
'Z'};
IEnumerable<char> ascending = letters.OrderBy(x => x);
// returns { ' ', '!', '+', '1', '9', '?', 'A', 'B', 'Y', 'Z', '[', 'a', 'b', 'y', 'z', '{' }
Esempio:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
OrderByDescending
https://riptutorial.com/it/home 781
Quando il valore è un numero intero , doppio o float inizia con il valore massimo , il che significa
che si ottengono prima i valori positivi, che zero e afterwords i valori negativi (vedere Esempio 1).
Quando ordini per char, il metodo confronta i valori ascii dei caratteri per ordinare la raccolta (vedi
Esempio 2).
Questo tipo di ordine è chiamato discendente, se lo vuoi viceversa hai bisogno di salire (vedi
OrderBy).
Esempio 1:
Esempio 2:
char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z',
'Z'};
IEnumerable<char> descending = letters.OrderByDescending(x => x);
// returns { '{', 'z', 'y', 'b', 'a', '[', 'Z', 'Y', 'B', 'A', '?', '9', '1', '+', '!', ' ' }
Esempio 3:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
concat
https://riptutorial.com/it/home 782
var result = foo.Concat(bar).ToList(); // 1,2,3,3,4,5
contiene
MSDN:
//Using the Person's Equals method - override Equals() and GetHashCode() - otherwise it
//will compare by reference and result will be false
var result4 = objects.Contains(new Person { Name = "Phil" }); // true
Un uso intelligente di Contains sarebbe quello di sostituire più clausole if in una chiamata
Contains .
https://riptutorial.com/it/home 783
Quindi, invece di fare questo:
Fai questo:
https://riptutorial.com/it/home 784
Capitolo 130: Reactive Extensions (Rx)
Examples
Osservazione dell'evento TextChanged su un controllo TextBox
Un osservabile viene creato dall'evento TextChanged del TextBox. Inoltre, qualsiasi input viene
selezionato solo se è diverso dall'ultimo input e se non vi è stato input entro 0,5 secondi. L'output
in questo esempio viene inviato alla console.
Observable
.FromEventPattern(textBoxInput, "TextChanged")
.Select(s => ((TextBox) s.Sender).Text)
.Throttle(TimeSpan.FromSeconds(0.5))
.DistinctUntilChanged()
.Subscribe(text => Console.WriteLine(text));
Observable
.Start(() => GetData())
.SelectMany(s => s)
.Buffer(bufferSize)
.ObserveOn(SynchronizationContext.Current)
.Subscribe(items =>
{
Console.WriteLine("Loaded {0} elements", items.Count);
https://riptutorial.com/it/home 785
Leggi Reactive Extensions (Rx) online: https://riptutorial.com/it/csharp/topic/5770/reactive-
extensions--rx-
https://riptutorial.com/it/home 786
Capitolo 131: Regex Parsing
Sintassi
• new Regex(pattern); // Crea una nuova istanza con un modello definito.
• Regex.Match(input); // Avvia la ricerca e restituisce la corrispondenza.
• Regex.Matches(input); // Avvia la ricerca e restituisce un MatchCollection
Parametri
Nome Dettagli
Il modello di string che deve essere utilizzato per la ricerca. Per maggiori
Modello
informazioni: msdn
Osservazioni
Hai bisogno di usare
using System.Text.RegularExpressions;
Bello avere
• Puoi testare i tuoi modelli online senza la necessità di compilare la tua soluzione per
ottenere risultati qui: Fai clic su di me
• Regex101 Esempio: clic me
Soprattutto i principianti tendono a sovraffaticare i loro compiti con regex perché si sente potente e
nel posto giusto per ricerche più complesse basate sul testo. Questo è il punto in cui le persone
cercano di analizzare i documenti xml con espressioni regolari senza nemmeno chiedere a se
stessi se ci potrebbe essere una classe già finita per questo compito come XmlDocument .
Regex dovrebbe essere l'ultima arma per raccogliere la complessità di nuovo. Almeno non
dimenticarti di mettere in atto uno sforzo per cercare la right way prima di scrivere 20 linee di
https://riptutorial.com/it/home 787
modelli.
Examples
Partita singola
using System.Text.RegularExpressions;
Risultato:
Più partite
using System.Text.RegularExpressions;
Risultato:
found = new List<string>() { "text in here", "another one", "third one", "fourth" }
https://riptutorial.com/it/home 788
Capitolo 132: Rendere sicuro un thread
variabile
Examples
Controllo dell'accesso a una variabile in un ciclo Parallel.Per
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main( string[] args )
{
object sync = new object();
int sum = 0;
Parallel.For( 1, 1000, ( i ) => {
lock( sync ) sum = sum + i; // lock is necessary
Non è sufficiente fare sum = sum + i senza il lock perché l'operazione read-modify-write non è
atomica. Un thread sovrascriverà tutte le modifiche esterne alla sum che si verificano dopo aver
letto il valore corrente della sum , ma prima che esso memorizzi il valore modificato di sum + i
nuovo in sum .
https://riptutorial.com/it/home 789
Capitolo 133: ricorsione
Osservazioni
Si noti che l'utilizzo della ricorsione può avere un impatto grave sul codice, poiché ogni chiamata
di funzione ricorsiva verrà aggiunta allo stack. Se ci sono troppe chiamate questo potrebbe portare
a un'eccezione StackOverflow . La maggior parte delle "funzioni ricorsive naturali" possono
essere scritti come for , while o foreach costrutto di ciclo, e pur non guardare in modo elegante o
intelligente sarà più efficiente.
Pensaci sempre due volte e usa ricorsione con attenzione - sappi perché lo usi:
• la ricorsione dovrebbe essere usata quando si sa che il numero di chiamate ricorsive non è
eccessivo
○ mezzi eccessivi , dipende da quanta memoria è disponibile
• la ricorsione viene utilizzata perché è una versione del codice più chiara e più pulita, è più
leggibile di una funzione iterativa o basata su loop. Spesso questo è il caso perché dà un
codice più pulito e più compatto (ovvero meno linee di codice).
○ ma attenzione, può essere meno efficiente! Ad esempio nella ricorsione di Fibonacci,
per calcolare l' ennesimo numero nella sequenza, il tempo di calcolo crescerà
esponenzialmente!
• https://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/recursion2.html
• https://en.wikipedia.org/wiki/Recursion#In_computer_science
Examples
Descrivere ricorsivamente una struttura dell'oggetto
La ricorsione è quando un metodo si chiama da solo. Preferibilmente lo farà finché non verrà
soddisfatta una condizione specifica e quindi uscirà normalmente dal metodo, ritornando al punto
da cui è stato chiamato il metodo. In caso contrario, potrebbe verificarsi un'eccezione di overflow
dello stack dovuta a troppe chiamate ricorsive.
/// <summary>
/// Create an object structure the code can recursively describe
/// </summary>
public class Root
{
public string Name { get; set; }
public ChildOne Child { get; set; }
}
public class ChildOne
{
public string ChildOneName { get; set; }
public ChildTwo Child { get; set; }
https://riptutorial.com/it/home 790
}
public class ChildTwo
{
public string ChildTwoName { get; set; }
}
/// <summary>
/// The console application with the recursive function DescribeTypeOfObject
/// </summary>
public class Program
{
static void Main(string[] args)
{
// point A, we call the function with type 'Root'
DescribeTypeOfObject(typeof(Root));
Console.WriteLine("Press a key to exit");
Console.ReadKey();
}
Un metodo che chiama se stesso finché non viene soddisfatta una condizione
specifica.
https://riptutorial.com/it/home 791
Passo dopo passo:
1. Il number (4) == 1 ?
2. No? return 4 * Factorial(number-1) (3)
3. Poiché il metodo viene chiamato ancora una volta, ripete ora il primo passo utilizzando
Factorial(3) come nuovo argomento.
4. Questo continua finché non viene eseguito Factorial(1) e number (1) == 1 restituisce 1.
5. Complessivamente, il calcolo "crea" 4 * 3 * 2 * 1 e infine restituisce 24.
La chiave per comprendere la ricorsione è che il metodo chiama una nuova istanza di se stesso.
Dopo il ritorno, l'esecuzione dell'istanza chiamante continua.
Uno degli usi della ricorsione consiste nel navigare attraverso una struttura gerarchica dei dati,
come un albero di directory del file system, senza sapere quanti livelli ha l'albero o il numero di
oggetti su ciascun livello. In questo esempio, vedrai come usare la ricorsione su un albero di
directory per trovare tutte le sottodirectory di una directory specificata e stampare l'intero albero
sulla console.
Console.WriteLine(
$"Getting directory tree of '{rootDirectorypath}'");
PrintDirectoryTree(rootDirectorypath);
Console.WriteLine("Press 'Enter' to quit...");
Console.ReadLine();
}
https://riptutorial.com/it/home 792
Console.WriteLine(e.Message);
}
}
Console.WriteLine($"{indentation}-{directory.Name}");
var nextLevel = currentLevel + 1;
try
{
foreach (var subDirectory in directory.GetDirectories())
{
PrintDirectoryTree(subDirectory, nextLevel);
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"{indentation}-{e.Message}");
}
}
}
Questo codice è un po 'più complicato del minimo indispensabile per completare questa attività,
poiché include il controllo delle eccezioni per gestire eventuali problemi con l'ottenimento delle
directory. Di seguito troverai una suddivisione del codice in segmenti più piccoli con le spiegazioni
di ciascuno.
Main :
Il metodo principale accetta un input da un utente come una stringa, che deve essere utilizzato
come percorso della directory principale. Quindi chiama il metodo PrintDirectoryTree con questa
stringa come parametro.
PrintDirectoryTree(string) :
Questo è il primo di due metodi che gestiscono la stampa dell'albero della directory effettiva.
Questo metodo prende una stringa che rappresenta il percorso della directory root come
parametro. Controlla se il percorso è una directory effettiva e, in caso contrario, genera una
DirectoryNotFoundException che viene quindi gestita nel blocco catch. Se il percorso è una directory
reale, una DirectoryInfo oggetto rootDirectory viene creato dal percorso, e la seconda
PrintDirectoryTree metodo viene chiamato con il rootDirectory oggetto e RootLevel , che è un
numero intero costante con un valore di zero.
PrintDirectoryTree(DirectoryInfo, int) :
Questo secondo metodo gestisce il peso del lavoro. Prende un DirectoryInfo e un intero come
parametri. DirectoryInfo è la directory corrente e il numero intero è la profondità della directory
https://riptutorial.com/it/home 793
relativa alla radice. Per facilità di lettura, l'output è indentato per ogni livello in profondità nella
directory corrente, in modo che l'output assomigli a questo:
-Root
-Child 1
-Child 2
-Grandchild 2.1
-Child 3
Una volta stampata la directory corrente, vengono recuperate le sottodirectory e questo metodo
viene quindi chiamato su ciascuno di essi con un valore del livello di profondità superiore a quello
corrente. Quella parte è la ricorsione: il metodo che si autodefinisce. Il programma verrà eseguito
in questo modo finché non avrà visitato tutte le directory dell'albero. Quando ha raggiunto una
directory senza subdirectory, il metodo restituirà automaticamente.
Questo metodo rileva anche una UnauthorizedAccessException , che viene generata se una delle
sottodirectory della directory corrente è protetta dal sistema. Il messaggio di errore viene stampato
al livello di indentazione corrente per coerenza.
Questo non include lo specifico controllo degli errori o la formattazione dell'output del primo
approccio, ma fa effettivamente la stessa cosa. Poiché utilizza solo stringhe anziché DirectoryInfo
, non può fornire l'accesso ad altre proprietà di directory come le autorizzazioni.
Sequenza di Fibonacci
https://riptutorial.com/it/home 794
return 1;
}
// Recursive case. Return the sum of the two previous Fibonacci numbers.
// This works because the definition of the Fibonacci sequence specifies
// that the sum of two adjacent elements equals the next element.
return fib(i - 2) + fib(i - 1);
fib(10); // Returns 55
Calcolo fattoriale
Il fattoriale di un numero (indicato con!, Come per esempio 9!) È la moltiplicazione di quel numero
con il fattoriale di uno inferiore. Quindi, per esempio, 9! = 9 x 8! = 9 x 8 x 7! = 9 x 8 x 7 x 6 x 5 x 4 x
3 x 2 x 1.
long Factorial(long x)
{
if (x < 1)
{
throw new OutOfRangeException("Factorial can only be used with positive numbers.");
}
if (x == 1)
{
return 1;
} else {
return x * Factorial(x - 1);
}
}
Calcolo PowerOf
Il calcolo della potenza di un dato numero può essere eseguito in modo ricorsivo. Dato un numero
base n ed esponente e , dobbiamo assicurarci di dividere il problema in blocchi diminuendo
l'esponente e .
Esempio teorico:
• 2² = 2x2
• 2³ = 2x2x2 o, 2³ = 2² x 2
Qui sta il segreto del nostro algoritmo ricorsivo (vedi il codice sotto). Si tratta di prendere il
problema e separarlo in blocchi più piccoli e più semplici da risolvere.
• Gli appunti
○ quando il numero di base è 0, dobbiamo essere consapevoli di restituire 0 come 0³ = 0
x0x0
○ quando l'esponente è 0, dobbiamo essere consapevoli di restituire sempre 1, in quanto
questa è una regola matematica.
https://riptutorial.com/it/home 795
Esempio di codice:
[Theory]
[MemberData(nameof(PowerOfTestData))]
public void PowerOfTest(int @base, int exponent, int expected) {
Assert.Equal(expected, CalcPowerOf(@base, exponent));
}
https://riptutorial.com/it/home 796
Capitolo 134: Riflessione
introduzione
Reflection è un meccanismo in linguaggio C # per accedere alle proprietà degli oggetti dinamici in
runtime. In genere, reflection viene utilizzato per recuperare le informazioni sul tipo di oggetto
dinamico e sui valori degli attributi dell'oggetto. Nell'applicazione REST, ad esempio, è possibile
utilizzare la riflessione per scorrere l'oggetto di risposta serializzato.
Nota: in base alle linee guida MS, il codice critico delle prestazioni dovrebbe evitare la riflessione.
Vedere https://msdn.microsoft.com/en-us/library/ff647790.aspx
Osservazioni
Reflection consente al codice di accedere alle informazioni su assiemi, moduli e tipi in fase di
esecuzione (esecuzione del programma). Questo può quindi essere ulteriormente utilizzato per
creare, modificare o accedere dinamicamente ai tipi. I tipi includono proprietà, metodi, campi e
attributi.
Ulteriori letture:
Riflessione (C #)
Examples
Ottieni un System.Type
using System;
using System.Reflection;
using System.Linq;
https://riptutorial.com/it/home 797
public static void Main()
{
var members = typeof(object)
.GetMembers(BindingFlags.Public |
BindingFlags.Static |
BindingFlags.Instance);
Possiamo anche utilizzare GetMembers() senza passare BindingFlags . Ciò restituirà tutti i membri
pubblici di quel tipo specifico.
Una cosa da notare che GetMembers non restituisce i membri in alcun ordine particolare, quindi non
fare mai affidamento sull'ordine che GetMembers ti restituisce.
Visualizza la demo
using System;
https://riptutorial.com/it/home 798
Produzione:
inferno
Visualizza la demo
Produzione:
7,38905609893065
Visualizza la demo
Utilizzo di base:
int newValue = 1;
// set the value myInstance.myProperty to newValue
prop.setValue(myInstance, newValue);
L'impostazione delle proprietà di sola lettura implementate automaticamente può essere effettuata
tramite il relativo campo di supporto (in .NET Framework il nome del campo di supporto è
"k__BackingField"):
int newValue = 1;
// set the value of myInstance.myProperty backing field to newValue
fieldInfo.SetValue(myInstance, newValue);
Attributi personalizzati
https://riptutorial.com/it/home 799
Trova tutti gli attributi personalizzati su una determinata proprietà
/// <summary>
/// Returns the value of a member attribute for any member in a class.
/// (a member is a Field, Property, Method, etc...)
/// <remarks>
/// If there is more than one member of the same name in the class, it will return the
first one (this applies to overloaded methods)
/// </remarks>
/// <example>
/// Read System.ComponentModel Description Attribute from method 'MyMethodName' in
class 'MyClass':
/// var Attribute = typeof(MyClass).GetAttribute("MyMethodName",
(DescriptionAttribute d) => d.Description);
/// </example>
/// <param name="type">The class that contains the member as a type</param>
/// <param name="MemberName">Name of the member in the class</param>
/// <param name="valueSelector">Attribute type and property to get (will return first
instance if there are multiple attributes of the same type)</param>
/// <param name="inherit">true to search this member's inheritance chain to find the
attributes; otherwise, false. This parameter is ignored for properties and events</param>
/// </summary>
public static TValue GetAttribute<TAttribute, TValue>(this Type type, string
MemberName, Func<TAttribute, TValue> valueSelector, bool inherit = false) where TAttribute :
Attribute
{
var att =
type.GetMember(MemberName).FirstOrDefault().GetCustomAttributes(typeof(TAttribute),
inherit).FirstOrDefault() as TAttribute;
if (att != null)
{
return valueSelector(att);
}
return default(TValue);
}
}
uso
https://riptutorial.com/it/home 800
'MyClass'
var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) =>
d.Description);
Se si dispone di un'istanza di un tipo generico ma per qualche motivo non si conosce il tipo
specifico, è possibile determinare gli argomenti generici che sono stati utilizzati per creare questa
istanza.
Supponiamo che qualcuno abbia creato un'istanza di List<T> come tale e lo trasmetta a un
metodo:
quindi al momento della compilazione non hai idea di quali argomenti generici sono stati usati per
creare o . Reflection fornisce molti metodi per ispezionare i tipi generici. Inizialmente, possiamo
determinare se il tipo di o è del tutto generico:
Type t = o.GetType();
if (!t.IsGenericType) return;
...
Ma questo non è tutto ciò che vogliamo sapere. List<> è un tipo generico. Ma vogliamo solo
esaminare le istanze di specifici tipi generici costruiti . Un tipo generico costruito è ad esempio un
List<int> che ha un argomento di tipo specifico per tutti i suoi parametri generici.
https://riptutorial.com/it/home 801
distinguere questi tipi generici costruiti da definizioni di tipi generici:
typeof(List<>).IsGenericType // true
typeof(List<>).IsGenericTypeDefinition // true
typeof(List<>).IsConstructedGenericType// false
typeof(List<int>).IsGenericType // true
typeof(List<int>).IsGenericTypeDefinition // false
typeof(List<int>).IsConstructedGenericType// true
Int32
Diciamo che hai lezione con metodi generici. E devi chiamare le sue funzioni con la riflessione.
Sample sample = new Sample();//or you can get an instance via reflection
Per il metodo statico non hai bisogno di un'istanza. Quindi anche il primo argomento sarà nullo.
https://riptutorial.com/it/home 802
MethodInfo method = typeof(Sample).GetMethod("StaticMethod");
MethodInfo generic = method.MakeGenericMethod(typeof(string));
generic.Invoke(null, null);
Se si desidera che l'applicazione per supportare un sistema di plug-in, ad esempio per caricare i
plugin da assemblee situati in plugins cartella:
interface IPlugin
{
string PluginDescription { get; }
void DoWork();
}
Il caricatore di plugin dell'applicazione troverà i file dll, otterrà tutti i tipi in quegli assembly che
implementano IPlugin e ne creerà istanze.
https://riptutorial.com/it/home 803
Creazione di un'istanza di un tipo
Tuttavia, anche se le prestazioni di Activator sono state migliorate da .NET 3.5, l'uso di
Activator.CreateInstance() è un'opzione errata a volte, a causa di prestazioni (relativamente)
basse: Test 1 , Test 2 , Test 3 ...
Il metodo MakeGenericType trasforma un tipo generico aperto (come List<> ) in un tipo concreto
(come List<string> ) applicando argomenti tipo ad esso.
// To create a List<string>
Type[] tArgs = { typeof(string) };
Type target = openType.MakeGenericType(tArgs);
https://riptutorial.com/it/home 804
T GetInstance<T>() where T : new()
{
T instance = new T();
return instance;
}
// Get the instance of the desired constructor (here it takes a string as a parameter).
ConstructorInfo c = typeof(T).GetConstructor(new[] { typeof(string) });
// Don't forget to check if such constructor exists
if (c == null)
throw new InvalidOperationException(string.Format("A constructor for type '{0}' was not
found.", typeof(T)));
T instance = (T)c.Invoke(new object[] { "test" });
Gli alberi di espressione rappresentano il codice in una struttura dati ad albero, in cui ogni nodo è
un'espressione. Come spiega MSDN :
L'espressione è una sequenza di uno o più operandi e zero o più operatori che
possono essere valutati in un singolo valore, oggetto, metodo o spazio dei nomi. Le
espressioni possono essere costituite da un valore letterale, un'invocazione di metodo,
un operatore e i suoi operandi o un nome semplice. I nomi semplici possono essere il
nome di una variabile, un membro del tipo, un parametro del metodo, uno spazio dei
nomi o un tipo.
public GenericFactory()
{
_registeredTypes = new Dictionary<TKey, Func<object[], TType>>();
}
/// <summary>
/// Find and register suitable constructor for type
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="key">Key for this constructor</param>
/// <param name="parameters">Parameters</param>
public void Register(TKey key, params Type[] parameters)
{
ConstructorInfo ci = typeof(TType).GetConstructor(BindingFlags.Public |
BindingFlags.Instance, null, CallingConventions.HasThis, parameters, new ParameterModifier[] {
}); // Get the instance of ctor.
if (ci == null)
throw new InvalidOperationException(string.Format("Constructor for type '{0}'
was not found.", typeof(TType)));
https://riptutorial.com/it/home 805
lock (_locker)
{
if (!_registeredTypes.TryGetValue(key, out ctor)) // check if such ctor
already been registered
{
var pExp = Expression.Parameter(typeof(object[]), "arguments"); // create
parameter Expression
var ctorParams = ci.GetParameters(); // get parameter info from
constructor
argExpressions[i] = block;
}
else
argExpressions[i] = Expression.Convert(indexedAcccess,
parameters[i]);
}
var newExpr = Expression.New(ci, argExpressions); // create expression
that represents call to specified ctor with the specified arguments.
/// <summary>
/// Returns instance of registered type by key.
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="key"></param>
/// <param name="args"></param>
/// <returns></returns>
public TType Create(TKey key, params object[] args)
https://riptutorial.com/it/home 806
{
Func<object[], TType> foo;
if (_registeredTypes.TryGetValue(key, out foo))
{
return (TType)foo(args);
}
Utilizzo di FormatterServices.GetUninitializedObject
T instance = (T)FormatterServices.GetUninitializedObject(typeof(T));
Per fare questo è necessario un riferimento all'assembly che contiene il tipo. Se hai un altro tipo
disponibile che sai è nello stesso assembly di quello che desideri, puoi farlo:
typeof(KnownType).Assembly.GetType(typeName);
• dove typeName è il nome del tipo che stai cercando (incluso lo spazio dei nomi), e KnownType è
il tipo che conosci è nello stesso assembly.
Type t = null;
foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
{
if (ass.FullName.StartsWith("System."))
https://riptutorial.com/it/home 807
continue;
t = ass.GetType(typeName);
if (t != null)
break;
}
Si noti il controllo per escludere gli assembly dello spazio dei nomi System di scansione per
velocizzare la ricerca. Se il tuo tipo potrebbe effettivamente essere un tipo CLR, dovrai eliminare
queste due righe.
Se ti capita di avere il nome completo del tipo completo di assembly incluso l'assembly, puoi
semplicemente farlo
Type.GetType(fullyQualifiedName);
Questa tecnica può essere estesa anche alle proprietà. Se abbiamo una classe chiamata MyClass
con una proprietà int nome MyIntProperty , il codice per ottenere un getter fortemente tipizzato
sarebbe (l'esempio seguente presuppone che 'target' sia un'istanza valida di MyClass ):
https://riptutorial.com/it/home 808
var theSetter = theProperty.GetSetMethod();
// Now get a strongly-typed delegate for MyIntProperty that can be executed against any
MyClass instance...
var stronglyTypedSetter = (Action<MyClass, int>)Delegate.CreateDelegate(typeof(Action<MyClass,
int>), theSetter);
// Set MyIntProperty to 5...
stronglyTypedSetter(target, 5);
https://riptutorial.com/it/home 809
Capitolo 135: Risoluzione di sovraccarico
Osservazioni
Il processo di risoluzione del sovraccarico è descritto nella specifica C # , sezione 7.5.3. Rilevanti
sono anche le sezioni 7.5.2 (inferenza del tipo) e 7.6.5 (espressioni di invocazione).
Examples
Esempio di sovraccarico di base
class Example
{
public static void Hello(int arg)
{
Console.WriteLine("int");
}
int
double
In fase di compilazione, quando il compilatore trova il metodo call Hello(0) , trova tutti i metodi con
il nome Hello . In questo caso, ne trova due. Quindi cerca di determinare quale dei metodi è
migliore . L'algoritmo per determinare quale metodo è migliore è complesso, ma in genere si
riduce a "generare il minor numero possibile di conversioni implicite".
Pertanto, nel caso di Hello(0) , non è necessaria alcuna conversione per il metodo Hello(int) ma
è necessaria una conversione numerica implicita per il metodo Hello(double) . Quindi, il primo
metodo è scelto dal compilatore.
https://riptutorial.com/it/home 810
Nel caso di Hello(0.0) , non esiste alcun modo per convertire implicitamente 0.0 in un int , quindi il
metodo Hello(int) non è nemmeno considerato per la risoluzione di sovraccarico. Rimane solo il
metodo e quindi viene scelto dal compilatore.
Il seguente programma:
class Program
{
static void Method(params Object[] objects)
{
System.Console.WriteLine(objects.Length);
}
static void Method(Object a, Object b)
{
System.Console.WriteLine("two");
}
static void Main(string[] args)
{
object[] objectArray = new object[5];
Method(objectArray);
Method(objectArray, objectArray);
Method(objectArray, objectArray, objectArray);
}
}
stamperà:
5
two
3
Se hai
https://riptutorial.com/it/home 811
void F1(MyType1 x) {
// do something
}
void F1(MyType2 x) {
// do something else
}
e per qualche motivo devi chiamare il primo overload di F1 ma con x = null , quindi fare
semplicemente
F1(null);
non verrà compilato poiché la chiamata è ambigua. Per contrastare ciò che puoi fare
F1(null as MyType1);
https://riptutorial.com/it/home 812
Capitolo 136: Runtime Compile
Examples
RoslynScript
CSharpCodeProvider
https://riptutorial.com/it/home 813
Capitolo 137: ruscello
Examples
Usando i flussi
Un flusso è un oggetto che fornisce un mezzo di basso livello per trasferire i dati. Loro stessi non
agiscono come contenitori di dati.
I dati che trattiamo sono in forma di array di byte ( byte [] ). Le funzioni di lettura e scrittura sono
tutte orientate ai byte, ad esempio WriteByte() .
Non ci sono funzioni per gestire interi, stringhe, ecc. Ciò rende lo stream molto generico, ma meno
semplice da utilizzare se, per esempio, si desidera semplicemente trasferire il testo. Gli stream
possono essere particolarmente utili quando si ha a che fare con una grande quantità di dati.
Dovremo utilizzare diversi tipi di stream in base ai quali deve essere scritto / letto (ad esempio il
backing store). Ad esempio, se la fonte è un file, dobbiamo usare FileStream :
fs.Close();
}
Allo stesso modo, System.Net.Sockets.NetworkStream viene utilizzato per l'accesso alla rete.
Tutti gli stream derivano dalla classe generica System.IO.Stream . I dati non possono essere letti o
scritti direttamente dai flussi. .NET Framework fornisce classi helper come StreamReader ,
StreamWriter , BinaryReader e BinaryWriter che convertono tra i tipi nativi e l'interfaccia di flusso di
basso livello e trasferiscono i dati al o dallo stream per te.
La lettura e la scrittura sugli stream possono essere eseguite tramite StreamReader e StreamWriter .
Si dovrebbe fare attenzione quando si chiudono questi. Per impostazione predefinita, la chiusura
chiuderà anche lo stream contenuto e lo renderà inutilizzabile per ulteriori utilizzi. Questo
https://riptutorial.com/it/home 814
comportamento predefinito può essere modificato utilizzando un costruttore che ha il parametro
bool leaveOpen e ne imposta il valore come true .
StreamWriter :
StreamReader :
https://riptutorial.com/it/home 815
Capitolo 138: Selezionato e deselezionato
Sintassi
• controllato (a + b) // espressione controllata
• deselezionata (a + b) // espressione non controllata
• controllato {c = a + b; c + = 5; } // blocco selezionato
• deselezionato {c = a + b; c + = 5; } // blocco deselezionato
Examples
Selezionato e deselezionato
short m = 32767;
short n = 32767;
int result1 = checked((short)(m + n)); //will throw an OverflowException
int result2 = unchecked((short)(m + n)); // will return -2
Se nessuno di questi viene specificato, il contesto predefinito si baserà su altri fattori, come le
opzioni del compilatore.
Le parole chiave possono anche creare ambiti per (dis) controllare più operazioni.
short m = 32767;
short n = 32767;
checked
{
int result1 = (short)(m + n); //will throw an OverflowException
}
unchecked
{
int result2 = (short)(m + n); // will return -2
}
https://riptutorial.com/it/home 816
Capitolo 139: Sequenze di escape delle
stringhe
Sintassi
• \ '- virgoletta singola (0x0027)
• \ "- virgolette doppie (0x0022)
• \\ - backslash (0x005C)
• \ 0 - null (0x0000)
• \ a - alert (0x0007)
• \ b - backspace (0x0008)
• \ f - form feed (0x000C)
• \ n - nuova riga (0x000A)
• \ r - ritorno a capo (0x000D)
• \ t - scheda orizzontale (0x0009)
• \ v - scheda verticale (0x000B)
• \ u0000 - \ uFFFF - Carattere Unicode
• \ x0 - \ xFFFF - Carattere Unicode (codice con lunghezza variabile)
• \ U00000000 - \ U0010FFFF - Carattere Unicode (per la generazione di surrogati)
Osservazioni
Le sequenze di escape di stringhe vengono trasformate nel carattere corrispondente in fase di
compilazione . Le stringhe ordinarie che contengono stringhe all'indietro non vengono
trasformate.
Console.WriteLine(escaped.Length); // 1
Console.WriteLine(notEscaped.Length); // 2
Console.WriteLine(notEscaped2.Length); // 2
Examples
Sequenze di escape dei caratteri Unicode
https://riptutorial.com/it/home 817
Scappare simboli speciali in caratteri letterali
Apostrophes
Barra rovesciata
Barra rovesciata
Il secondo esempio utilizza letteralmente una stringa letterale , che non considera la barra
rovesciata come un carattere di escape.
Citazioni
newlines
string s = "\c";
char c = '\c';
https://riptutorial.com/it/home 818
Invece, produrranno l'errore Unrecognized escape sequence al momento della compilazione.
e supponiamo che il carattere Œ non sia disponibile nella codifica dei caratteri che usi per i tuoi file
sorgente C #. Sei fortunato, è consentito utilizzare gli escape del tipo \u#### o \U######## in
identificatori nel codice. Quindi è legale scrivere:
(Tuttavia, potrebbe essere una buona idea passare a UTF-8 o una codifica simile in grado di
gestire tutti i caratteri.)
https://riptutorial.com/it/home 819
Capitolo 140: Serializzazione binaria
Osservazioni
Il motore di serializzazione binario fa parte del framework .NET, ma gli esempi qui riportati sono
specifici di C #. Rispetto ad altri motori di serializzazione integrati nel framework .NET, il
serializzatore binario è veloce ed efficiente e di solito richiede pochissimo codice aggiuntivo per
farlo funzionare. Tuttavia, è anche meno tollerante alle modifiche al codice; cioè, se serializzi un
oggetto e poi apporti una leggera modifica alla definizione dell'oggetto, probabilmente non lo
deserializzi correttamente.
Examples
Rendere serializzabile un oggetto
[Serializable]
public class Vector
{
public int X;
public int Y;
public int Z;
[NonSerialized]
public decimal DontSerializeThis;
[OptionalField]
public string Name;
}
Tutti i membri verranno serializzati a meno che non si [NonSerialized] esplicitamente utilizzando
l'attributo [NonSerialized] . Nel nostro esempio, X , Y , Z e Name sono tutti serializzati.
Tutti i membri devono essere presenti alla deserializzazione a meno che non siano contrassegnati
con [NonSerialized] o [OptionalField] [NonSerialized] [OptionalField] . Nel nostro esempio, X , Y e
Z sono tutti richiesti e la deserializzazione fallirà se non sono presenti nello stream.
DontSerializeThis sarà sempre impostato su default(decimal) (che è 0). Se Name è presente nello
stream, verrà impostato su quel valore, altrimenti verrà impostato su default(string) (che è null).
Lo scopo di [OptionalField] è di fornire un po 'di tolleranza della versione.
Se si utilizza l'attributo [NonSerialized] , quel membro avrà sempre il suo valore predefinito dopo la
deserializzazione (ad esempio 0 per un int , null per string , false per un bool , ecc.),
Indipendentemente dall'inizializzazione eseguita nell'oggetto stesso (costruttori, dichiarazioni,
https://riptutorial.com/it/home 820
ecc.). Per compensare, vengono [OnDeserializing] gli attributi [OnDeserializing] (chiamato solo
BEFORE deserializing) e [OnDeserialized] (chiamato solo AFTER deserializing) insieme alle loro
controparti, [OnSerializing] e [OnSerialized] .
Supponiamo di voler aggiungere un "Rating" al nostro Vector e vogliamo assicurarci che il valore
inizi sempre a 1. Il modo in cui è scritto qui sotto, sarà 0 dopo essere stato deserializzato:
[Serializable]
public class Vector
{
public int X;
public int Y;
public int Z;
[NonSerialized]
public decimal Rating = 1M;
public Vector()
{
Rating = 1M;
}
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
Rating = 1M;
}
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
Rating = 1 + ((X+Y+Z)/3);
}
Allo stesso modo, possiamo controllare come vengono scritte le cose usando [OnSerializing] e
[OnSerialized] .
Ciò otterrebbe un maggiore controllo sulla serializzazione, su come salvare e caricare i tipi
https://riptutorial.com/it/home 821
[Serializable]
public class Item : ISerializable
{
private string _name;
public Item ()
{
Per la serializzazione dei dati, è possibile specificare il nome desiderato e il tipo desiderato
Inoltre consente di serializzare o deserializzare correttamente una classe che non è serializzabile
https://riptutorial.com/it/home 822
var item = (Item)obj;
item.Name = (string)info.GetValue("_name", typeof(string));
return item;
}
}
La soluzione completa
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinarySerializationExample
{
class Item
{
private string _name;
https://riptutorial.com/it/home 823
info.AddValue("_name", item.Name);
}
class Program
{
static void Main(string[] args)
{
var item = new Item
{
Name = "Orange"
};
https://riptutorial.com/it/home 824
Serialization Binder
Ora possiamo controllare quali tipi stanno caricando e su questa base per decidere cosa vogliamo
veramente ricevere
La soluzione completa
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinarySerializationExample
{
class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName.Equals("BinarySerializationExample.Item"))
return typeof(Item);
return null;
}
}
[Serializable]
public class Item
{
private string _name;
https://riptutorial.com/it/home 825
{
get { return _name; }
set { _name = value; }
}
}
class Program
{
static void Main(string[] args)
{
var item = new Item
{
Name = "Orange"
};
Questo piccolo esempio mostra come si può perdere la retrocompatibilità nei propri programmi se
non si presta attenzione a ciò. E i modi per ottenere un maggiore controllo del processo di
serializzazione
Versione 1
[Serializable]
class Data
{
[OptionalField]
private int _version;
https://riptutorial.com/it/home 826
public int Version
{
get { return _version; }
set { _version = value; }
}
}
E ora, supponiamo che nella seconda versione del programma sia stata aggiunta una nuova
classe. E abbiamo bisogno di memorizzarlo in un array.
Versione 2
[Serializable]
class NewItem
{
[OptionalField]
private string _name;
[Serializable]
class Data
{
[OptionalField]
private int _version;
[OptionalField]
private List<NewItem> _newItems;
https://riptutorial.com/it/home 827
}
}
Ottieni un'eccezione:
Perché?
L'ObjectManager ha una logica diversa per risolvere le dipendenze per gli array e per i tipi di
riferimento e valore. Abbiamo aggiunto una serie di nuovi il tipo di riferimento che è assente nel
nostro assembly.
E poiché questo tipo non è nell'assembly e le dipendenze non possono essere riparate. Per
qualche ragione, non rimuove la matrice dall'elenco di elementi per le correzioni e alla fine genera
un'eccezione "IncorrectNumberOfFixups".
Sono alcuni "trucchi" nel processo di serializzazione. Per qualche ragione, non funziona
correttamente solo per le matrici di nuovi tipi di riferimento.
A Note:
https://riptutorial.com/it/home 828
Similar code will work correctly if you do not use arrays with new classes
• Usa una collezione di nuove strutture piuttosto che classi o usa un dizionario (possibili
classi), perché un dizionario è una raccolta di keyvaluepair (è la struttura)
• Usa ISerializable, se non puoi modificare il vecchio codice
https://riptutorial.com/it/home 829
Capitolo 141: straripamento
Examples
Overflow intero
C'è una capacità massima che un numero intero può memorizzare. E quando supererai quel
limite, tornerà al lato negativo. Per int , è 2147483647
Per tutti gli interi al di fuori di questo intervallo utilizzare lo spazio dei nomi System.Numerics che
ha il tipo di dati BigInteger. Controlla sotto il link per maggiori informazioni
https://msdn.microsoft.com/en-us/library/system.numerics.biginteger(v=vs.110).aspx
Puoi evitarlo usando 1L. Ora 1 sarà long e l'aggiunta sarà una long aggiunta
Ordinare è importante
int x = int.MaxValue;
Console.WriteLine(x + x + 1L); //prints -1
int x = int.MaxValue;
Console.WriteLine(x + 1L + x); //prints 4294967295
https://riptutorial.com/it/home 830
Ciò è dovuto all'ordinamento da sinistra a destra delle operazioni. Nel primo frammento di codice x
+ x trabocca e dopo diventa long . D'altra parte x + 1L diventa long e dopo che x viene aggiunto a
questo valore.
https://riptutorial.com/it/home 831
Capitolo 142: String Concatenate
Osservazioni
Se stai creando una stringa dinamica, è buona norma optare per la classe StringBuilder piuttosto
che unire stringhe usando il metodo + o Concat poiché ogni + / Concat crea un nuovo oggetto
stringa ogni volta che viene eseguito.
Examples
+ Operatore
string s1 = "string1";
string s2 = "string2";
Il metodo String.Join può essere utilizzato per concatenare più elementi da una matrice di
stringhe.
https://riptutorial.com/it/home 832
string separator = ", ";
Questo esempio utilizza il String.Join(String, String[], Int32, Int32) , che specifica l'indice
iniziale e il conteggio in cima al separatore e al valore.
Se non si desidera utilizzare startIndex e contare sovraccarichi, è possibile unire tutte le stringhe
fornite. Come questo:
che produrrà;
https://riptutorial.com/it/home 833
Capitolo 143: String.Format
introduzione
I metodi Format sono una serie di overload nella classe System.String utilizzata per creare stringhe
che combinano oggetti in rappresentazioni di stringa specifiche. Queste informazioni possono
essere applicate a String.Format , a vari metodi WriteLine e ad altri metodi nel framework .NET.
Sintassi
• string.Format (formato stringa, oggetto params [] args)
• string.Format (provider IFormatProvider, formato stringa, oggetto params [] args)
• $ "stringa {testo} blablabla" // Poiché C # 6
Parametri
Parametro Dettagli
Una stringa di formato composita , che definisce il modo in cui gli argomenti
formato
devono essere combinati in una stringa.
Una raccolta di modi per formattare gli oggetti alle stringhe. I valori tipici
fornitore
includono CultureInfo.InvariantCulture and CultureInfo.CurrentCulture .
Osservazioni
Gli appunti:
Examples
Luoghi in cui String.Format è "incorporato" nel framework
Esistono diversi punti in cui è possibile utilizzare String.Format indirettamente : il segreto è cercare
il sovraccarico con il string format, params object[] args firma string format, params object[] args
, ad esempio:
https://riptutorial.com/it/home 834
Console.WriteLine(String.Format("{0} - {1}", name, value));
NumberFormatInfo può essere utilizzato per formattare sia numeri interi che numeri a virgola mobile.
// invariantResult is "1,234,567.89"
var invarianResult = string.Format(CultureInfo.InvariantCulture, "{0:#,###,##}", 1234567.89);
// customResult is "1_GS_234_GS_567_NS_89"
var customResult = string.Format(customProvider, "{0:#,###.##}", 1234567.89);
if (format == "Reverse")
{
return String.Join("", arg.ToString().Reverse());
}
return arg.ToString();
}
Uso:
https://riptutorial.com/it/home 835
String.Format(new CustomFormat(), "-> {0:Reverse} <-", "Hello World");
Produzione:
Il secondo valore nelle parentesi graffe determina la lunghezza della stringa di sostituzione.
Regolando il secondo valore come positivo o negativo, è possibile modificare l'allineamento della
stringa.
Produzione:
Formati numerici
// Decimals
string.Format("Decimal, fixed precision: {0:0.000}; as percents: {0:0.00%}", 0.12);
Produzione:
L'identificatore di formato "c" (o valuta) converte un numero in una stringa che rappresenta un
importo in valuta.
https://riptutorial.com/it/home 836
Precisione
Il valore predefinito è 2. Usa c1, c2, c3 e così via per controllare la precisione.
Simbolo di valuta
1. Passa l'istanza di CultureInfo per usare il simbolo di cultura personalizzato.
2. Usa qualsiasi stringa come simbolo di valuta. Usa NumberFormatInfo per personalizzare il
simbolo di valuta.
L'utilizzo del pattern negativo è lo stesso del pattern positivo. Molto più casi d'uso si prega di fare
riferimento al link originale.
https://riptutorial.com/it/home 837
nfi.CurrencyPositivePattern = 0;
nfi.CurrencyDecimalSeparator = "..";
string.Format(nfi, "{0:C}", 112.236677); //$112..24
6.0
Dal momento che C # 6.0 è possibile utilizzare l'interpolazione delle stringhe al posto di
String.Format .
Console.Write(String.Format("{0:dd}",date));
6.0
Console.Write($"{date:ddd}");
produzione :
06
Лхагва
06
https://riptutorial.com/it/home 838
specifier Senso Campione Risultato
ss secondi {0:ss} 14
TT AM PM {0:tt} PM
https://riptutorial.com/it/home 839
specifier Senso Campione Risultato
Accordare()
Il metodo ToString () è presente su tutti i tipi di oggetti di riferimento. Ciò è dovuto al fatto che tutti i
tipi di riferimento derivano da Object su cui è presente il metodo ToString (). Il metodo ToString ()
sulla classe base dell'oggetto restituisce il nome del tipo. Il frammento seguente stamperà
"Utente" sulla console.
...
Tuttavia, la classe User può anche sovrascrivere ToString () per modificare la stringa restituita. Il
frammento di codice sottostante stampa "Id: 5, Name: User1" sulla console.
...
Mentre il metodo String.Format() è certamente utile per la formattazione dei dati come stringhe,
https://riptutorial.com/it/home 840
può spesso essere un po 'eccessivo, specialmente quando si ha a che fare con un singolo oggetto
come mostrato di seguito:
Un approccio più semplice potrebbe essere quello di utilizzare semplicemente il metodo ToString()
disponibile su tutti gli oggetti all'interno di C #. Supporta tutte le stesse stringhe di formattazione
standard e personalizzate , ma non richiede la mappatura dei parametri necessaria in quanto ci
sarà un solo argomento:
Per ottenere lo stesso comportamento con il metodo ToString() , è necessario utilizzare un altro
metodo come PadLeft() o PadRight() rispettivamente:
https://riptutorial.com/it/home 841
Capitolo 144: StringBuilder
Examples
Che cos'è un oggetto StringBuilder e quando usarne uno
Un StringBuilder rappresenta una serie di caratteri, che a differenza di una stringa normale, sono
mutabili. Spesso è necessario modificare le stringhe che abbiamo già creato, ma l'oggetto stringa
standard non è mutabile. Ciò significa che ogni volta che una stringa viene modificata, è
necessario creare un nuovo oggetto stringa, copiarlo e quindi riassegnarlo.
• Creare una nuova matrice di caratteri uguale alla lunghezza di myString e alla nuova stringa
che stiamo aggiungendo.
• Copia tutti i caratteri di myString all'inizio del nostro nuovo array e copia la nuova stringa nella
fine dell'array.
• Crea un nuovo oggetto stringa in memoria e riassegnalo a myString .
Per una singola concatenazione, questo è relativamente banale. Tuttavia, cosa succederebbe se
fosse necessario eseguire molte operazioni di accodamento, ad esempio in un ciclo?
A causa della copia ripetuta e della creazione di oggetti, ciò determinerà un degrado significativo
delle prestazioni del nostro programma. Possiamo evitarlo usando invece un StringBuilder .
Ora, quando viene eseguito lo stesso ciclo, le prestazioni e la velocità del tempo di esecuzione del
programma saranno significativamente più veloci rispetto all'utilizzo di una stringa normale. Per
ripristinare StringBuilder in una stringa normale, possiamo semplicemente chiamare il metodo
ToString() di StringBuilder .
Tuttavia, questa non è l'unica ottimizzazione che StringBuilder ha. Per ottimizzare ulteriormente le
funzioni, possiamo sfruttare altre proprietà che aiutano a migliorare le prestazioni.
https://riptutorial.com/it/home 842
StringBuilder sb = new StringBuilder(10000); // initializes the capacity to 10000
Se sappiamo in anticipo quanto deve essere il nostro StringBuilder , possiamo specificare la sua
dimensione in anticipo, il che impedirà di ridimensionare l'array di caratteri che ha internamente.
sb.Append('k', 2000);
Sebbene l'uso di StringBuilder per l'aggiunta sia molto più veloce di una stringa, può essere
eseguito anche più velocemente se è necessario aggiungere un singolo carattere molte volte.
Una volta completata la creazione della stringa, è possibile utilizzare il metodo ToString() su
StringBuilder per convertirlo in una string base. Questo è spesso necessario perché la classe
StringBuilder non eredita dalla string .
In conclusione, StringBuilder dovrebbe essere usato al posto della stringa quando è necessario
apportare molte modifiche a una stringa con le prestazioni in mente.
return customerNamesCsv.ToString();
}
https://riptutorial.com/it/home 843
Capitolo 145: Stringhe Verbatim
Sintassi
• @ "le stringhe verbatim sono stringhe il cui contenuto non è sfuggito, quindi in questo caso \
n non rappresenta il carattere di nuova riga ma due caratteri individuali: \ e n Le stringhe di
Verbatim vengono create precedendo il contenuto della stringa con il carattere @"
Osservazioni
Per concatenare i valori letterali stringa, utilizzare il simbolo @ all'inizio di ogni stringa.
Examples
Stringhe multilinea
multiline paragraph";
Produzione:
Questo è un
paragrafo multilinea
Anche le stringhe multilinea che contengono virgolette possono essere sfuggite come se fossero
su una singola riga, perché sono stringhe letterali.
""San Diego""
Si noti che gli spazi / tabulazioni all'inizio delle righe 2 e 3 qui sono effettivamente presenti nel
valore della variabile; controlla questa domanda per possibili soluzioni.
https://riptutorial.com/it/home 844
Escaping Double Quotes
Le doppie virgolette all'interno di stringhe letterali possono essere sfuggite utilizzando 2 virgolette
doppie "" per rappresentare una virgoletta doppia " nella stringa risultante.
Produzione:
Le stringhe Verbatim possono essere combinate con le nuove funzionalità di interpolazione String
trovate in C # 6.
Console.WriteLine($@"Testing \n 1 2 {5 - 2}
New line");
Produzione:
Test \ n 1 2 3
Nuova linea
Come previsto da una stringa testuale, i backslash vengono ignorati come caratteri di escape. E
come previsto da una stringa interpolata, qualsiasi espressione all'interno di parentesi graffe viene
valutata prima di essere inserita nella stringa in quella posizione.
In una stringa normale, il carattere backslash è il carattere di escape, che indica al compilatore di
guardare il / i carattere / i successivo / i per determinare il carattere effettivo nella stringa. ( Elenco
completo di caratteri escape )
Nelle stringhe letterali, non ci sono caratteri di escape (eccetto per "" che è trasformato in un " ).
Per usare una stringa testuale, basta anteporre un @ prima delle virgolette iniziali.
Produzione:
https://riptutorial.com/it/home 845
c: \ temp \ newfile.txt
che produrrà:
c: emp
ewfile.txt
usando caratteri che escaping. (Il \t viene sostituito con un carattere di tabulazione e \n viene
sostituito con un carattere di fine riga.)
https://riptutorial.com/it/home 846
Capitolo 146: Structs
Osservazioni
A differenza delle classi, una struct è un tipo di valore, e viene creata sullo stack locale e non
sull'heap gestito, per impostazione predefinita . Ciò significa che una volta che lo stack specifico
esce dall'ambito, la struct viene struct . Anche i tipi di riferimento struct nenti alle struct vengono
spazzati, una volta che il GC determina che non sono più riferiti dalla struct .
structs non può ereditare e non può essere base per ereditarietà, sono implicitamente sigillate e
non possono includere membri protected . Tuttavia, una struct può implementare un'interfaccia,
come fanno le classi.
Examples
Dichiarazione di una struttura
• struct campi istanza struct possono essere impostati tramite un costruttore parametrizzato
o singolarmente dopo la costruzione di struct .
• Le strutture vengono copiate sull'assegnazione, ovvero tutti i dati vengono copiati nella
nuova istanza e le modifiche a una di esse non vengono riflesse dall'altra.
• Una struct non può essere null , sebbene possa essere usato come un tipo nullable:
https://riptutorial.com/it/home 847
Vector v1 = null; //illegal
Vector? v2 = null; //OK
Nullable<Vector> v3 = null // OK
• Le strutture possono essere istanziate con o senza l'utilizzo del new operatore.
Vector v2;
v2.X = 1;
v2.Y = 2;
v2.Z = 3;
Una struct può dichiarare tutto ciò che una classe può dichiarare, con alcune eccezioni:
• Una struct non può dichiarare un costruttore senza parametri. struct campi istanza struct
possono essere impostati tramite un costruttore parametrizzato o singolarmente dopo la
costruzione di struct . I membri privati possono essere inizializzati solo dal costruttore.
• Una struct non può dichiarare i membri come protetti, dal momento che è implicitamente
sigillato.
• I campi Struct possono essere inizializzati solo se costanti o statici.
Struct utilizzo
Con il costruttore:
https://riptutorial.com/it/home 848
Point point2 = new Point(0.5, 0.6);
Senza costruttore:
Vector v1;
v1.Y = 2;
v1.Z = 3;
Vector v1;
v1.X = 1;
v1.Y = 2;
v1.Z = 3;
Point point3;
point3.x = 0.5;
point3.y = 0.6;
Se usiamo una struct con il suo costruttore, non avremo problemi con il campo non assegnato
(ogni campo non assegnato ha valore null).
A differenza delle classi, non è necessario costruire una struttura, ovvero non è necessario
utilizzare la nuova parola chiave, a meno che non sia necessario chiamare uno dei costruttori.
Una struct non richiede la nuova parola chiave perché è un tipo di valore e quindi non può essere
nullo.
Le strutture sinse sono tipi di valore, tutti i dati vengono copiati durante l'assegnazione e qualsiasi
modifica alla nuova copia non modifica i dati per la copia originale. Il frammento di codice
https://riptutorial.com/it/home 849
seguente mostra che p1 è copiato in p2 e le modifiche apportate su p1 non influenzano l'istanza di
p2 .
Console.WriteLine($"{p1.x} {p1.y}"); // 1 2
var p2 = p1;
Console.WriteLine($"{p2.x} {p2.y}"); // Same output: 1 2
p1.x = 3;
Console.WriteLine($"{p1.x} {p1.y}"); // 3 2
Console.WriteLine($"{p2.x} {p2.y}"); // p2 remain the same: 1 2
https://riptutorial.com/it/home 850
Capitolo 147:
System.DirectoryServices.Protocols.LdapConnec
Examples
Connessione LDAP SSL autenticata, il certificato SSL non corrisponde al DNS
inverso
// Specific to your company. Might start "cn=manager" instead of "ou=people", for example.
private const string CompanyDN = "ou=people,dc=example,dc=com";
// Configure server and port. LDAP w/ SSL, aka LDAPS, uses port 636.
// If you don't have SSL, don't give it the SSL port.
LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier(TargetServer, 636);
https://riptutorial.com/it/home 851
Utilizzare il server LDAP, ad es. Cercare qualcuno tramite userid per tutti i valori objectClass.
L'oggetto objectClass è presente per dimostrare una ricerca composta: la e commerciale è
l'operatore booleano "e" per le due clausole di query.
Per usare la connessione, qualcosa del genere avrebbe portato le persone al cognome Smith
https://riptutorial.com/it/home 852
Capitolo 148:
System.Management.Automation
Osservazioni
Lo spazio dei nomi System.Management.Automation è lo spazio dei nomi di root per
Windows PowerShell.
Examples
Richiama la semplice pipeline sincrona
// add command
ps.AddCommand("Get-Date");
// run command(s)
Console.WriteLine("Date: {0}", ps.Invoke().First());
Console.ReadLine();
}
}
https://riptutorial.com/it/home 853
Leggi System.Management.Automation online: https://riptutorial.com/it/csharp/topic/4988/system-
management-automation
https://riptutorial.com/it/home 854
Capitolo 149: Task Libreria parallela
Examples
Parallel.ForEach
Un esempio che utilizza il ciclo Parallel.ForEach per eseguire il ping di un determinato array di
URL del sito Web.
if (result.Status == System.Net.NetworkInformation.IPStatus.Success)
{
Console.WriteLine(string.Format("{0} is online", url));
}
});
}
Parallel.For
Un esempio che utilizza Parallel.Per il ciclo per eseguire il ping di una determinata matrice di URL
del sito Web.
https://riptutorial.com/it/home 855
if (result.Status == System.Net.NetworkInformation.IPStatus.Success)
{
Console.WriteLine(string.Format("{0} is online", urls[i]));
}
});
}
Parallel.Invoke
System.Threading.Tasks.Parallel.Invoke(
() => PingUrl(urls[0]),
() => PingUrl(urls[1]),
() => PingUrl(urls[2]),
() => PingUrl(urls[3])
);
}
if (result.Status == System.Net.NetworkInformation.IPStatus.Success)
{
Console.WriteLine(string.Format("{0} is online", url));
}
}
public Foo()
{
this._cts = new CancellationTokenSource();
}
https://riptutorial.com/it/home 856
public void CancelExecution()
{
this._cts.Cancel();
}
/// <summary>
/// "Infinite" loop that runs every N seconds. Good for checking for a heartbeat or
updates.
/// </summary>
/// <param name="taskState">The cancellation token from our _cts field, passed in the
StartNew call</param>
private async void OwnCodeCancelableTask_EveryNSeconds(object taskState)
{
var token = (CancellationToken)taskState;
while (!token.IsCancellationRequested)
{
Console.WriteLine("Do the work that needs to happen every N seconds in this
loop");
// Passing token here allows the Delay to be cancelled if your task gets
cancelled.
await Task.Delay(TASK_ITERATION_DELAY_MS, token);
}
}
}
public Foo()
{
this._cts = new CancellationTokenSource();
}
/// <summary>
/// "Infinite" loop with no delays. Writing to a database while pulling from a buffer for
example.
/// </summary>
/// <param name="taskState">The cancellation token from our _cts field, passed in the
StartNew call</param>
private void OwnCodeCancelableTask(object taskState)
{
var token = (CancellationToken) taskState; //Our cancellation token passed from
StartNew();
https://riptutorial.com/it/home 857
while ( !token.IsCancellationRequested )
{
Console.WriteLine("Do your task work in this loop");
}
}
}
if (result.Status == System.Net.NetworkInformation.IPStatus.Success)
{
response = $"{url} is online";
}
return response;
}
https://riptutorial.com/it/home 858
Capitolo 150: threading
Osservazioni
Un thread è una parte di un programma che può essere eseguito indipendentemente dalle altre
parti. Può eseguire attività contemporaneamente con altri thread. Il multithreading è una
funzionalità che consente ai programmi di eseguire l'elaborazione simultanea in modo che sia
possibile eseguire più di una operazione alla volta.
Le applicazioni multithread sono più reattive all'input dell'utente e sono anche facilmente scalabili,
poiché lo sviluppatore può aggiungere thread come e quando il carico di lavoro aumenta.
Per controllare l'operazione di un thread, CLR delega una funzione al sistema operativo noto
come Thread Scheduler. Uno scheduler di thread assicura che tutti i thread siano assegnati al
tempo di esecuzione corretto. Controlla inoltre che i thread bloccati o bloccati non consumino gran
parte del tempo di CPU.
Thread è la classe principale nello spazio dei nomi System.Threading . Altre classi includono
AutoResetEvent , Interlocked , Monitor , Mutex e ThreadPool .
Alcuni dei delegati presenti nello spazio dei nomi System.Threading includono ThreadStart ,
TimerCallback e WaitCallback .
Examples
https://riptutorial.com/it/home 859
Semplice demo di threading completa
class Program
{
static void Main(string[] args)
{
// Create 2 thread objects. We're using delegates because we need to pass
// parameters to the threads.
var thread1 = new Thread(new ThreadStart(() => PerformAction(1)));
var thread2 = new Thread(new ThreadStart(() => PerformAction(2)));
Console.WriteLine("Done");
Console.ReadKey();
}
class Program
{
static void Main(string[] args)
{
// Run 2 Tasks.
var task1 = Task.Run(() => PerformAction(1)));
var task2 = Task.Run(() => PerformAction(2)));
// Wait (i.e. block this thread) until both Tasks are complete.
Task.WaitAll(new [] { task1, task2 });
Console.WriteLine("Done");
Console.ReadKey();
}
https://riptutorial.com/it/home 860
var rnd = new Random(id);
for (int i = 0; i < 100; i++)
{
Console.WriteLine("Task: {0}: {1}", id, i);
Thread.Sleep(rnd.Next(0, 1000));
}
}
}
Se stai eseguendo più calcoli lunghi, puoi eseguirli contemporaneamente su diversi thread sul tuo
computer. Per fare ciò, creiamo un nuovo Thread e puntiamo a un metodo diverso.
using System.Threading;
class MainClass {
static void Main() {
var thread = new Thread(Secondary);
https://riptutorial.com/it/home 861
thread.Start();
}
using System.Threading;
class MainClass {
static void Main() {
var thread = new Thread(Secondary);
thread.Start("SecondThread");
}
Il CLR pianificherà quindi ogni thread su un processore logico, questo teoricamente potrebbe
significare ogni thread su un processore logico diverso, tutti i thread su un singolo processore
logico o qualche altra combinazione.
using System;
using System.Threading;
class MainClass {
static void Main() {
for (int i = 0; i < Environment.ProcessorCount; i++) {
var thread = new Thread(Secondary);
thread.Start(i);
}
A volte, vuoi che i tuoi thread condividano simultaneamente i dati. Quando ciò accade, è
importante conoscere il codice e bloccare le parti che potrebbero andare storte. Di seguito viene
https://riptutorial.com/it/home 862
mostrato un semplice esempio di conteggio di due thread.
using System.Threading;
class MainClass
{
static int count { get; set; }
Per risolvere questo problema, dobbiamo bloccare il valore del conteggio, in modo che più thread
diversi non possano leggere e scrivere allo stesso tempo. Con l'aggiunta di un blocco e una
chiave, possiamo impedire ai thread di accedere ai dati simultaneamente.
using System.Threading;
class MainClass
{
https://riptutorial.com/it/home 863
}
Se si dispone di un ciclo foreach che si desidera velocizzare e non si preoccupa di quale ordine è
l'output, è possibile convertirlo in un ciclo foreach parallelo attenendosi alla seguente procedura:
using System;
using System.Threading;
using System.Threading.Tasks;
Un deadlock è ciò che si verifica quando due o più thread sono in attesa di completamento o di
rilascio di una risorsa in modo tale da attendere per sempre.
https://riptutorial.com/it/home 864
Uno scenario tipico di due thread in attesa di completamento è quando un thread GUI di Windows
Form attende un thread di lavoro e il thread worker tenta di richiamare un oggetto gestito dal
thread della GUI. Osservare che con questo codice exmaple, facendo clic su button1 si bloccherà
il programma.
Per ovviare a questo, si può usare un modo non bloccante di invocare la casella di testo invece:
Tuttavia, ciò causerà problemi se è necessario eseguire il codice che dipende dalla casella di
testo che viene aggiornata per prima. In tal caso, eseguilo come parte del richiamo, ma tieni
presente che questo lo farà girare sul thread della GUI.
In alternativa, avvia un nuovo thread intero e lascia che quello faccia l'attesa sul thread della GUI,
in modo che workthread possa essere completato.
https://riptutorial.com/it/home 865
{
// Do work
Thread workerthread2 = new Thread(() =>
{
textBox1.Invoke(new Action(() => textBox1.Text = "Some Text"));
// Do work dependent on textBox1 being updated first,
// start another worker thread or raise an event
});
workerthread2.Start();
// Do work that is not dependent on textBox1 being updated first
}
Per ridurre al minimo il rischio di imbattersi in un deadlock di attesa reciproca, evitare sempre i
riferimenti circolari tra i thread quando possibile. Una gerarchia di thread in cui i thread di livello
inferiore lasciano solo i messaggi per i thread di livello superiore e non li attendono mai non si
imbatteranno in questo tipo di problema. Tuttavia, sarebbe comunque vulnerabile ai deadlock
basati sul blocco delle risorse.
Un deadlock è ciò che si verifica quando due o più thread sono in attesa di completamento o di
rilascio di una risorsa in modo tale da attendere per sempre.
Se thread1 contiene un blocco sulla risorsa A e attende che la risorsa B venga rilasciata mentre
thread2 contiene la risorsa B e attende che la risorsa A venga rilasciata, sono bloccati.
Facendo clic sul pulsante 1 per il seguente codice di esempio, la tua applicazione entrerà in uno
stato di stallo imprevisto e si bloccherà
string output;
https://riptutorial.com/it/home 866
thread2.Join();
return output;
}
Per evitare di essere bloccati in questo modo, è possibile utilizzare Monitor.TryEnter (lock_object,
timeout_in_milliseconds) per verificare se un blocco è già presente su un oggetto. Se
Monitor.TryEnter non riesce ad acquisire un lock su lock_object prima di timeout_in_milliseconds,
restituisce false, dando al thread la possibilità di rilasciare altre risorse detenute e cedendo, dando
così agli altri thread la possibilità di completare come in questa versione leggermente modificata di
quanto sopra :
string output;
https://riptutorial.com/it/home 867
thread1.Start();
thread2.Start();
}
Si noti che questa soluzione alternativa si basa sul fatto che thread2 è testardo sui blocchi e che
thread1 è disposto a fornire, in modo che thread2 abbia sempre la precedenza. Si noti inoltre che
thread1 deve rifare il lavoro che ha svolto dopo aver bloccato la risorsa A, quando produce.
Pertanto, sii cauto nell'implementare questo approccio con più di un thread di rendimento, poiché
rischierai di entrare in un cosiddetto livelock - uno stato che si verificherebbe se due thread
continuassero a fare il primo bit del loro lavoro e poi si cedere reciprocamente , ricominciare più
volte.
https://riptutorial.com/it/home 868
Capitolo 151: Timer
Sintassi
• myTimer.Interval - imposta la frequenza con cui viene chiamato l'evento "Tick" (in
millisecondi)
• myTimer.Enabled - valore booleano che imposta il timer su abilitato / disabilitato
• myTimer.Start() - Avvia il timer.
• myTimer.Stop() - Ferma il timer.
Osservazioni
Se si utilizza Visual Studio, i timer possono essere aggiunti come controllo direttamente al modulo
dalla casella degli strumenti.
Examples
Timer multithread
Esempio: un timer chiama il metodo DataWrite, che scrive "multithread eseguito ..." dopo che
sono trascorsi cinque secondi, e quindi ogni secondo dopo che l'utente preme Invio:
using System;
using System.Threading;
class Program
{
static void Main()
{
// First interval = 5000ms; subsequent intervals = 1000ms
Timer timer = new Timer (DataWrite, "multithread executed...", 5000, 1000);
Console.ReadLine();
timer.Dispose(); // This both stops the timer and cleans up.
}
Nota: pubblicherà una sezione separata per lo smaltimento dei timer multithread.
Change : questo metodo può essere chiamato quando si desidera modificare l'intervallo del timer.
Timeout.Infinite - Se vuoi sparare solo una volta. Specificare questo nell'ultimo argomento del
costruttore.
https://riptutorial.com/it/home 869
System.Timers - Un'altra classe di timer fornita da .NET Framework. Termina System.Threading.Timer
.
Caratteristiche:
• IComponent : consente di posizionarlo nella barra dei componenti del Designer di Visual
Studio
• Proprietà Interval invece di un metodo Change
• event Elapsed anziché un delegate richiamata
• Proprietà Enabled per avviare e arrestare il timer ( default value = false )
• Start e Stop metodi nel caso in cui ti venga confusa la proprietà Enabled (punto precedente)
• AutoReset - per indicare un evento ricorrente ( default value = true )
• Proprietà SynchronizingObject con i metodi Invoke e BeginInvoke per chiamare in sicurezza i
metodi su elementi WPF e controlli Windows Form
using System;
using System.Timers; // Timers namespace rather than Threading
class SystemTimer
{
static void Main()
{
Timer timer = new Timer(); // Doesn't require any args
timer.Interval = 500;
timer.Elapsed += timer_Elapsed; // Uses an event instead of a delegate
timer.Start(); // Start the timer
Console.ReadLine();
timer.Stop(); // Stop the timer
Console.ReadLine();
timer.Start(); // Restart the timer
Console.ReadLine();
timer.Dispose(); // Permanently stop the timer
}
Multithreaded timers : utilizzare il pool di thread per consentire a pochi thread di servire molti timer.
Significa che il metodo di callback o l'evento Elapsed può attivarsi su un thread diverso ogni volta
che viene chiamato.
Elapsed : questo evento si attiva sempre in tempo, indipendentemente dal fatto che l'evento Elapsed
precedente abbia completato l'esecuzione. Per questo motivo, callback o gestori di eventi devono
essere thread-safe. La precisione dei timer multithread dipende dal sistema operativo ed è in
genere compresa tra 10 e 20 ms.
- quando hai bisogno di maggiore precisione, usa questo e chiama il timer multimediale di
interop
Windows. Questo ha una precisione fino a 1 ms ed è definito in winmm.dll .
https://riptutorial.com/it/home 870
timeBeginPeriod: chiamate prima questo per informare il sistema operativo che è necessaria
un'accuratezza dei tempi elevata
timeEndPeriod - Chiama questo per informare l'OS che non hai più bisogno di un'accuratezza dei
tempi elevata.
Puoi trovare esempi completi su Internet che utilizzano il timer multimediale cercando le parole
chiave dllimport winmm.dll timesetevent .
I timer sono utilizzati per eseguire attività a intervalli di tempo specifici (Do X ogni Y secondi) Di
seguito è riportato un esempio di creazione di una nuova istanza di un Timer.
NOTA : questo vale per i timer che utilizzano WinForms. Se si utilizza WPF, è possibile esaminare
DispatcherTimer
public Form1()
{
InitializeComponent();
}
public Form1()
{
InitializeComponent();
https://riptutorial.com/it/home 871
private void myTimer_Tick(object sender, EventArgs e)
{
// Perform your actions here.
}
}
public Form1()
{
InitializeComponent();
if (timeLeft < 0)
{
myTimer.Stop();
}
}
}
Risultati in ...
https://riptutorial.com/it/home 872
E così via...
https://riptutorial.com/it/home 873
Capitolo 152: Tipi anonimi
Examples
Creare un tipo anonimo
Poiché i tipi anonimi non vengono denominati, le variabili di questi tipi devono essere digitate
implicitamente ( var ).
Se i nomi dei membri non sono specificati, vengono impostati sul nome della proprietà / variabile
utilizzata per inizializzare l'oggetto.
int foo = 1;
int bar = 2;
var anon2 = new { foo, bar };
// anon2.foo == 1
// anon2.bar == 2
Si noti che i nomi possono essere omessi solo quando l'espressione nella dichiarazione del tipo
anonimo è un semplice accesso alla proprietà; per le chiamate ai metodi o le espressioni più
complesse, è necessario specificare un nome di proprietà.
Anonimo vs dinamico
I tipi anonimi consentono la creazione di oggetti senza dover definire esplicitamente i loro tipi in
anticipo, mantenendo il controllo di tipo statico.
Al contrario, dynamic ha il controllo dinamico dei tipi, optando per gli errori di runtime, invece degli
errori di compilazione.
https://riptutorial.com/it/home 874
Metodi generici con tipi anonimi
Ciò significa che le espressioni LINQ possono essere utilizzate con tipi anonimi:
L'utilizzo di costruttori generici richiederebbe il nome dei tipi anonimi, il che non è possibile. In
alternativa, è possibile utilizzare metodi generici per consentire l'inferenza del tipo.
Nel caso di List<T> , gli array implicitamente tipizzati possono essere convertiti in un List<T>
tramite il metodo LINQ ToList :
L'uguaglianza di tipo anonimo è data dal metodo di istanza Equals . Due oggetti sono uguali se
hanno lo stesso tipo e valori uguali (attraverso a.Prop.Equals(b.Prop) ) per ogni proprietà.
https://riptutorial.com/it/home 875
Due tipi anonimi sono considerati uguali se e solo se le loro proprietà hanno lo stesso nome e tipo
e appaiono nello stesso ordine.
Le matrici di tipi anonimi possono essere create con una digitazione implicita.
https://riptutorial.com/it/home 876
Capitolo 153: Tipi incorporati
Examples
Tipo di riferimento immutabile - stringa
// single character s
char c = 's';
Tipo di valore: breve, int, lungo (con segno 16 bit, 32 bit, numeri interi a 64 bit)
// assigning a signed long to its minimum value (note the long postfix)
long l = -9223372036854775808L;
https://riptutorial.com/it/home 877
// assigning a signed long to its maximum value (note the long postfix)
long l = 9223372036854775807L;
È anche possibile rendere nullable di questi tipi, il che significa che in aggiunta ai normali valori
può essere assegnato anche null. Se una variabile di un tipo nullable non è inizializzata, sarà null
invece di 0. I tipi di nullità sono contrassegnati aggiungendo un punto interrogativo (?) Dopo il tipo.
Tipo di valore: ushort, uint, ulong (interi senza segno a 16 bit, 32 bit, 64 bit)
// assigning an unsigned long to its minimum value (note the unsigned long postfix)
ulong l = 0UL;
// assigning an unsigned long to its maximum value (note the unsigned long postfix)
ulong l = 18446744073709551615UL;
È anche possibile rendere nullable di questi tipi, il che significa che in aggiunta ai normali valori
può essere assegnato anche null. Se una variabile di un tipo nullable non è inizializzata, sarà null
invece di 0. I tipi di nullità sono contrassegnati aggiungendo un punto interrogativo (?) Dopo il tipo.
La parola chiave bool è un alias di System.Boolean. È usato per dichiarare le variabili per
memorizzare i valori booleani, true e false .
https://riptutorial.com/it/home 878
Confronti con i tipi di valore in scatola
Se i tipi di valore sono assegnati a variabili di tipo object , vengono inseriti in una scatola : il valore
viene archiviato in un'istanza di System.Object . Questo può portare a conseguenze indesiderate
quando si confrontano i valori con == , ad esempio:
Questo può essere evitato usando il metodo Equals sovraccarico, che darà il risultato atteso.
In alternativa, lo stesso potrebbe essere fatto unboxing delle variabili left e right modo che i
valori int vengano confrontati:
I tipi di valore in box possono essere disgiunti solo nel loro Type originale, anche se una
conversione dei due Type è valida, ad esempio:
Questo può essere evitato con il primo unboxing nel Type originale, ad esempio:
https://riptutorial.com/it/home 879
Capitolo 154: Tipo di conversione
Osservazioni
La conversione del tipo sta convertendo un tipo di dati in un altro tipo. È anche noto come tipo di
fusione. In C #, il casting del tipo ha due forme:
Conversione implicita del tipo : queste conversioni vengono eseguite da C # in modo sicuro per
i tipi. Ad esempio, sono le conversioni da tipi interi e conversioni da più piccoli a più grandi da
classi derivate a classi base.
Conversione esplicita del tipo : queste conversioni vengono eseguite esplicitamente dagli utenti
che utilizzano le funzioni predefinite. Le conversioni esplicite richiedono un operatore di cast.
Examples
Esempio di operatore implicito MSDN
class Digit
{
public Digit(double d) { val = d; }
public double val;
class Program
{
static void Main(string[] args)
{
Digit dig = new Digit(7);
//This call invokes the implicit "double" operator
double num = dig;
//This call invokes the implicit "Digit" operator
Digit dig2 = 12;
Console.WriteLine("num = {0} dig2 = {1}", num, dig2.val);
Console.ReadLine();
}
}
Produzione:
https://riptutorial.com/it/home 880
Digita per raddoppiare la conversione implicita chiamata
Conversazione implicita da doppia a cifra chiamata
num = 7 dig2 = 12
using System;
namespace TypeConversionApplication
{
class ExplicitConversion
{
static void Main(string[] args)
{
double d = 5673.74;
int i;
https://riptutorial.com/it/home 881
Capitolo 155: Tipo di valore vs Tipo di
riferimento
Sintassi
• Passando per riferimento: public void Double (ref int numberToDouble) {}
Osservazioni
introduzione
Tipi di valore
I tipi di valore sono i più semplici dei due. I tipi di valore sono spesso usati per rappresentare i dati
stessi. Un numero intero, un punto booleano o un punto nello spazio 3D sono tutti esempi di buoni
valori.
I tipi di valore (structs) sono dichiarati usando la parola chiave struct. Vedere la sezione della
sintassi per un esempio su come dichiarare una nuova struttura.
In generale, abbiamo 2 parole chiave che vengono utilizzate per dichiarare i tipi di valore:
• Structs
• enumerazioni
Tipi di riferimento
I tipi di riferimento sono leggermente più complessi. I tipi di riferimento sono oggetti tradizionali nel
senso della programmazione orientata agli oggetti. Quindi, supportano l'ereditarietà (e i benefici
che ne derivano) e supportano anche i finalizzatori.
• Classi
• I delegati
• interfacce
Nuovi tipi di riferimento (classi) sono dichiarati usando la parola chiave class. Per un esempio,
vedere la sezione della sintassi su come dichiarare un nuovo tipo di riferimento.
Major Differences
Di seguito sono riportate le principali differenze tra tipi di riferimento e tipi di valore.
https://riptutorial.com/it/home 882
Esistono tipi di valore nello stack, esistono tipi di riferimento sull'heap
Questa è la differenza spesso menzionata tra i due, ma in realtà, ciò a cui si riduce è che quando
si utilizza un tipo di valore in C #, ad esempio un int, il programma utilizzerà quella variabile per
fare riferimento direttamente a quel valore. Se dici int mine = 0, la variabile mine si riferisce
direttamente a 0, che è efficiente. Tuttavia, i tipi di riferimento effettivamente contengono (come
suggerisce il nome) un riferimento all'oggetto sottostante, questo è simile ai puntatori in altri
linguaggi come C ++.
Potresti non notare immediatamente gli effetti di questo, ma gli effetti sono lì, sono potenti e sono
sottili. Vedere l'esempio sulla modifica dei tipi di riferimento altrove per un esempio.
Questa differenza è la ragione principale per le seguenti altre differenze, e vale la pena
conoscere.
Quando un tipo di valore viene passato in un metodo come parametro, se il metodo modifica il
valore in qualsiasi modo, il valore non viene modificato Al contrario, passando un tipo di
riferimento nello stesso metodo e cambiandolo si cambia l'oggetto sottostante, in modo che altre
cose che usano lo stesso oggetto avranno l'oggetto appena cambiato piuttosto che il loro valore
originale.
Vedi l'esempio dei tipi di valore rispetto ai tipi di riferimento nei metodi per maggiori informazioni.
Semplicemente passali nel tuo metodo usando la parola chiave "ref", e quindi stai passando
questo oggetto per riferimento. Significato, è lo stesso oggetto in memoria. Quindi le modifiche
che apporti saranno rispettate. Vedere l'esempio sul passaggio per riferimento per un esempio.
Praticamente come si dice, è possibile assegnare un valore nullo a un tipo di riferimento, nel
senso che alla variabile assegnata non può essere assegnato alcun oggetto reale. Nel caso di tipi
di valore, tuttavia, ciò non è possibile. Tuttavia, puoi usare Nullable, per consentire al tuo tipo di
valore di essere annullabile, se questo è un requisito, anche se questo è qualcosa che stai
considerando, pensa fortemente se una classe potrebbe non essere l'approccio migliore qui, se è
il tuo genere.
Examples
Modifica dei valori altrove
https://riptutorial.com/it/home 883
var studentList = new List<Student>();
studentList.Add(new Student("Scott", "Nuke"));
studentList.Add(new Student("Vincent", "King"));
studentList.Add(new Student("Craig", "Bertt"));
Si noterà che anche se l'elenco delle liste di stampa è stato creato prima delle correzioni ai nomi
degli studenti dopo gli errori di battitura, il metodo PrintPrintingList stampa ancora i nomi corretti:
Scott Duke
Vincent Kong
Craig Brett
Questo perché entrambe le liste contengono un elenco di riferimenti agli stessi studenti. COSÌ,
cambiando l'oggetto studente sottostante si propaga agli usi da entrambe le liste.
https://riptutorial.com/it/home 884
public static void Main(string[] args)
{
...
DoubleNumber(ref number); // calling code
Console.WriteLine(number); // outputs 8
...
}
Apportare queste modifiche renderebbe il numero di aggiornamento come previsto, il che significa
che l'output della console per il numero sarebbe 8.
Dalla documentazione :
In C #, gli argomenti possono essere passati ai parametri per valore o per riferimento.
Il passaggio per riferimento abilita membri di funzioni, metodi, proprietà, indicizzatori,
operatori e costruttori per modificare il valore dei parametri e mantenere tale modifica
nell'ambiente di chiamata. Per passare un parametro per riferimento, utilizzare il ref o
out parola chiave.
La differenza tra ref e out è che out significa che il parametro passato deve essere assegnato
prima della fine della funzione. I parametri di contrasto passati con ref possono essere modificati
o lasciati invariati.
using System;
class Program
{
static void Main(string[] args)
{
int a = 20;
Console.WriteLine("Inside Main - Before Callee: a = {0}", a);
Callee(a);
Console.WriteLine("Inside Main - After Callee: a = {0}", a);
Console.ReadLine();
}
https://riptutorial.com/it/home 885
Console.WriteLine("Inside Callee a : {0}", a);
}
Uscita :
assegnazione
Assegnare a una variabile di una List<int> non crea una copia della List<int> . Invece, copia il
riferimento alla List<int> . Chiamiamo tipi che si comportano in questo modo tipi di riferimento .
Esistono due modi possibili per passare un tipo di valore per riferimento: ref e out . La differenza è
che passandolo con ref il valore deve essere inizializzato ma non quando lo si passa out .
L'utilizzo di out assicura che la variabile abbia un valore dopo la chiamata al metodo:
https://riptutorial.com/it/home 886
value += 4 // CS0269: Use of unassigned out parameter `value'
Console.WriteLine(nameof(ByOut) + value); // CS0269: Use of unassigned out parameter
`value'
value = 4;
Console.WriteLine(nameof(ByOut) + value);
}
int outValue2 = 10; // does not make any sense for out
ByOut(out outValue2); // prints 4
}
int refValue2 = 0;
ByRef(ref refValue2); // prints 0 and 4
Il problema è che utilizzando out il parametro must essere inizializzato prima di lasciare il metodo,
quindi il seguente metodo è possibile con ref ma non con out :
Codice
class Program
{
https://riptutorial.com/it/home 887
static void Main(string[] args)
{
int a = 20;
Console.WriteLine("Inside Main - Before Callee: a = {0}", a);
Callee(a);
Console.WriteLine("Inside Main - After Callee: a = {0}", a);
Console.WriteLine();
Produzione
https://riptutorial.com/it/home 888
Capitolo 156: Tipo dinamico
Osservazioni
La parola chiave dynamic dichiara una variabile il cui tipo non è noto al momento della
compilazione. Una variabile dynamic può contenere qualsiasi valore e il tipo di valore può cambiare
durante il runtime.
Come notato nel libro "Metaprogramming in .NET", C # non ha un tipo di supporto per la parola
chiave dynamic :
Examples
Creare una variabile dinamica
foo = "123";
Console.WriteLine(foo + 234);
// 123234
Console.WriteLine(foo.ToUpper()):
// NOW A STRING
Tornando dinamico
using System;
https://riptutorial.com/it/home 889
}
using System;
using System.Dynamic;
Console.WriteLine(info.Another);
// 456
Console.WriteLine(info.DoesntExist);
// Throws RuntimeBinderException
class IfElseExample
{
public string DebugToString(object a)
{
if (a is StringBuilder)
{
return DebugToStringInternal(a as StringBuilder);
}
else if (a is List<string>)
{
return DebugToStringInternal(a as List<string>);
}
else
{
return a.ToString();
}
}
https://riptutorial.com/it/home 890
class DynamicExample
{
public string DebugToString(object a)
{
return DebugToStringInternal((dynamic)a);
}
Il vantaggio per la dinamica, è l'aggiunta di un nuovo tipo da gestire richiede solo l'aggiunta di un
sovraccarico di DebugToStringInternal del nuovo tipo. Elimina anche la necessità di eseguirne
manualmente il cast nel tipo.
https://riptutorial.com/it/home 891
Capitolo 157: Uguale e GetHashCode
Osservazioni
Ogni implementazione di Equals deve soddisfare i seguenti requisiti:
Implementazioni di GetHashCode :
• Compatibile con Equals : se due oggetti sono uguali (ovvero che Equals restituisce true),
allora GetHashCode deve restituire lo stesso valore per ognuno di essi.
• Ampio intervallo : se due oggetti non sono uguali ( Equals dice false), ci dovrebbe essere
un'alta probabilità che i loro codici hash siano distinti. Spesso l'hashing perfetto non è
possibile in quanto esiste un numero limitato di valori tra cui scegliere.
• Economico : dovrebbe essere poco costoso calcolare il codice hash in tutti i casi.
Examples
Predefinito Comportamento uguale.
https://riptutorial.com/it/home 892
• Se l'istanza è un tipo di riferimento, Equals restituirà true solo se i riferimenti sono uguali.
• Se l'istanza è un tipo di valore, Equals restituirà true solo se il tipo e il valore sono uguali.
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
//areFooClassEqual: False
Foo fooClass1 = new Foo("42");
Foo fooClass2 = new Foo("42");
bool areFooClassEqual = fooClass1.Equals(fooClass2);
Console.WriteLine("fooClass1 and fooClass2 are equal: {0}", areFooClassEqual);
//False
//areFooIntEqual: True
int fooInt1 = 42;
int fooInt2 = 42;
bool areFooIntEqual = fooInt1.Equals(fooInt2);
Console.WriteLine("fooInt1 and fooInt2 are equal: {0}", areFooIntEqual);
//areFooStringEqual: True
string fooString1 = "42";
string fooString2 = "42";
bool areFooStringEqual = fooString1.Equals(fooString2);
Console.WriteLine("fooString1 and fooString2 are equal: {0}", areFooStringEqual);
}
}
un'istanza casuale
se il tuo metodo restituisce lo stesso numero intero (ad es. la costante '999') per ogni
○
https://riptutorial.com/it/home 893
○ Questi NON sono hash crittografici, dove la lentezza è una caratteristica
○ più lenta è la tua funzione hash, più lento è il tuo dizionario
• deve restituire lo stesso HashCode su due istanze che Equals restituisce true
○ se non lo fanno (es. perché GetHashCode restituisce un numero casuale), gli elementi
potrebbero non essere trovati in un List , Dictionary o simile.
Un buon metodo per implementare GetHashCode consiste nell'utilizzare un numero primo come
valore iniziale e aggiungere gli hashcode dei campi del tipo moltiplicato per altri numeri primi a
quello:
Solo i campi che sono usati in Equals -method dovrebbero essere usati per la funzione hash.
var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };
https://riptutorial.com/it/home 894
{
var person = obj as Person;
if(person == null) return false;
return Name == person.Name && Age == person.Age; //the clothes are not important when
comparing two persons
}
var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };
Anche usando LINQ per fare query diverse su persone controllerà sia Equals che GetHashCode :
https://riptutorial.com/it/home 895
comparing two persons;
}
Si noti che per questa query, due oggetti sono stati considerati uguali se entrambi gli Equals
restituito true e il GetHashCode ha restituito lo stesso codice hash per le due persone.
https://riptutorial.com/it/home 896
Capitolo 158: Una panoramica delle collezioni
c#
Examples
HashSet
utilizza una tabella hash, in modo che le ricerche siano estremamente veloci,
HashSet.Contains
indipendentemente dal numero di elementi nella raccolta.
SortedSet
// add something
// note that we add 2 before we add 1
mySet.Add(2);
mySet.Add(1);
// output:
// 1
// 2
T [] (Matrice di T)
https://riptutorial.com/it/home 897
}
// output:
// one
// two
// output:
// something else
// two
Elenco
List<T> è un elenco di un determinato tipo. Gli articoli possono essere aggiunti, inseriti, rimossi e
indirizzati per indice.
using System.Collections.Generic;
List<T> può essere pensato come una matrice che è possibile ridimensionare. L'enumerazione
della raccolta in ordine è rapida, così come l'accesso ai singoli elementi tramite il loro indice. Per
accedere a elementi basati su alcuni aspetti del loro valore, o qualche altra chiave, un
Dictionary<T> fornirà una ricerca più rapida.
Dizionario
Dizionario <TKey, TValue> è una mappa. Per una determinata chiave ci può essere un valore nel
dizionario.
using System.Collections.Generic;
// Reading data
Console.WriteLine(people["John"]); // 30
Console.WriteLine(people["George"]); // throws KeyNotFoundException
https://riptutorial.com/it/home 898
int age;
if (people.TryGetValue("Mary", out age))
{
Console.WriteLine(age); // 35
}
Pila
// Pop removes the top element of the stack and returns it.
Console.WriteLine(stack.Pop()); // prints 8
Console.WriteLine(stack.Pop()); // prints 5
https://riptutorial.com/it/home 899
Console.WriteLine(stack.Pop()); // prints 3
Lista collegata
list.AddFirst(2);
// the list now is 2, 3, 5, 8
list.RemoveFirst();
// the list is now 3, 5, 8
list.RemoveLast();
// the list is now 3, 5
Coda
https://riptutorial.com/it/home 900
Capitolo 159: Uso della direttiva
Osservazioni
La parola chiave using è sia una direttiva (questo argomento) sia una dichiarazione.
Per l'istruzione using (vale a dire per incapsulare l'ambito di un oggetto IDisposable , assicurandosi
che al di fuori di tale ambito l'oggetto venga eliminato in modo pulito), vedere Utilizzo di Statement
.
Examples
Uso di base
using System;
using BasicStuff = System;
using Sayer = System.Console;
using static System.Console; //From C# 6
class Program
{
public static void Main()
{
System.Console.WriteLine("Ignoring usings and specifying full type name");
Console.WriteLine("Thanks to the 'using System' directive");
BasicStuff.Console.WriteLine("Namespace aliasing");
Sayer.WriteLine("Type aliasing");
WriteLine("Thanks to the 'using static' directive (from C# 6)");
}
}
using System.Text;
//allows you to access classes within this namespace such as StringBuilder
//without prefixing them with the namespace. i.e:
//...
var sb = new StringBuilder();
//instead of
var sb = new System.Text.StringBuilder();
using st = System.Text;
//allows you to access classes within this namespace such as StringBuilder
//prefixing them with only the defined alias and not the full namespace. i.e:
//...
var sb = new st.StringBuilder();
https://riptutorial.com/it/home 901
//instead of
var sb = new System.Text.StringBuilder();
6.0
Consente di importare un tipo specifico e utilizzare i membri statici del tipo senza qualificarli con il
nome del tipo. Questo mostra un esempio usando metodi statici:
// ...
string GetName()
{
WriteLine("Enter your name.");
return ReadLine();
}
namespace Geometry
{
public class Circle
{
public double Radius { get; set; };
Se si utilizzano più spazi dei nomi che possono avere classi con lo stesso nome (come
System.Random e UnityEngine.Random ), è possibile utilizzare un alias per specificare che Random
proviene da uno o l'altro senza dover utilizzare l'intero spazio dei nomi nella chiamata .
Per esempio:
using UnityEngine;
using System;
Ciò farà sì che il compilatore non sia sicuro di quale Random valuterà la nuova variabile come.
Invece, puoi fare:
using UnityEngine;
using System;
https://riptutorial.com/it/home 902
using Random = System.Random;
Questo non ti preclude di chiamare l'altro dal suo spazio dei nomi completo, come questo:
using UnityEngine;
using System;
using Random = System.Random;
rnd sarà una variabile System.Random e unityRandom sarà una variabile UnityEngine.Random .
È possibile utilizzare l' using per impostare un alias per uno spazio dei nomi o un tipo. Maggiori
dettagli possono essere trovati qui .
Sintassi:
Esempio:
https://riptutorial.com/it/home 903
Capitolo 160: Utilizzando json.net
introduzione
Utilizzo della classe JSONConverter di JSON.net .
Examples
Usando JsonConverter su valori semplici
Esempio utilizzando JsonCoverter per deserializzare la proprietà runtime dalla risposta api in un
oggetto intervallo nel modello Film
JSON (
http://www.omdbapi.com/?i=tt1663662)
{
Title: "Pacific Rim",
Year: "2013",
Rated: "PG-13",
Released: "12 Jul 2013",
Runtime: "131 min",
Genre: "Action, Adventure, Sci-Fi",
Director: "Guillermo del Toro",
Writer: "Travis Beacham (screenplay), Guillermo del Toro (screenplay), Travis Beacham
(story)",
Actors: "Charlie Hunnam, Diego Klattenhoff, Idris Elba, Rinko Kikuchi",
Plot: "As a war between humankind and monstrous sea creatures wages on, a former pilot and
a trainee are paired up to drive a seemingly obsolete special weapon in a desperate effort to
save the world from the apocalypse.",
Language: "English, Japanese, Cantonese, Mandarin",
Country: "USA",
Awards: "Nominated for 1 BAFTA Film Award. Another 6 wins & 46 nominations.",
Poster: "https://images-na.ssl-images-
amazon.com/images/M/MV5BMTY3MTI5NjQ4Nl5BMl5BanBnXkFtZTcwOTU1OTU0OQ@@._V1_SX300.jpg",
Ratings: [{
Source: "Internet Movie Database",
Value: "7.0/10"
},
{
Source: "Rotten Tomatoes",
Value: "71%"
},
{
Source: "Metacritic",
Value: "64/100"
}
],
Metascore: "64",
imdbRating: "7.0",
https://riptutorial.com/it/home 904
imdbVotes: "398,198",
imdbID: "tt1663662",
Type: "movie",
DVD: "15 Oct 2013",
BoxOffice: "$101,785,482.00",
Production: "Warner Bros. Pictures",
Website: "http://pacificrimmovie.com",
Response: "True"
}
Modello di film
using Project.Serializers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
namespace Project.Models
{
[DataContract]
public class Movie
{
public Movie() { }
[DataMember]
public int Id { get; set; }
[DataMember]
public string ImdbId { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public DateTime Released { get; set; }
[DataMember]
[JsonConverter(typeof(RuntimeSerializer))]
public TimeSpan Runtime { get; set; }
}
}
RuntimeSerializer
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
https://riptutorial.com/it/home 905
using System.Threading.Tasks;
namespace Project.Serializers
{
public class RuntimeSerializer : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(TimeSpan);
}
JToken jt = JToken.Load(reader);
String value = jt.Value<String>();
int timespanMin;
if(!Int32.TryParse(value, out timespanMin))
{
throw new NotSupportedException();
}
Chiamandolo
Movie m = JsonConvert.DeserializeObject<Movie>(apiResponse));
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
https://riptutorial.com/it/home 906
CollectFields(token);
}
Uso:
dimostrazione
Per questo oggetto JSON
{
"User": "John",
"Workdays": {
"Monday": true,
"Tuesday": true,
"Friday": false
},
"Age": 42
}
User: 'John'
Workdays.Monday: 'True'
Workdays.Tuesday: 'True'
Workdays.Friday: 'False'
Age: '42'
https://riptutorial.com/it/home 907
Leggi Utilizzando json.net online: https://riptutorial.com/it/csharp/topic/9879/utilizzando-json-net
https://riptutorial.com/it/home 908
Capitolo 161: Utilizzando la dichiarazione
introduzione
Fornisce una comoda sintassi che garantisce l'uso corretto di oggetti IDisposable .
Sintassi
• usando (usa e getta) {}
• utilizzando (IDisposable disposable = new MyDisposable ()) {}
Osservazioni
L'oggetto IDisposable using deve implementare l'interfaccia IDisposable .
Esempi più completi per l'implementazione IDisposable possono essere trovati nei documenti
MSDN .
Examples
Utilizzo delle nozioni di base sulle istruzioni
using dello zucchero sintattico consente di garantire che una risorsa venga pulita senza bisogno di
un blocco try-finally esplicito. Questo significa che il tuo codice sarà molto più pulito e non
perderai risorse non gestite.
Standard Dispose cleanup pattern, per gli oggetti che implementano l'interfaccia IDisposable (che la
classe base Stream FileStream esegue in .NET):
int Foo()
{
var fileName = "file.txt";
{
FileStream disposable = null;
https://riptutorial.com/it/home 909
try
{
disposable = File.Open(fileName, FileMode.Open);
return disposable.ReadByte();
}
finally
{
// finally blocks are always run
if (disposable != null) disposable.Dispose();
}
}
}
int Foo()
{
var fileName = "file.txt";
Proprio come i blocchi finally eseguono sempre indipendentemente da errori o ritorni, using
sempre chiamate Dispose() , anche in caso di errore:
int Foo()
{
var fileName = "file.txt";
Nota: Poiché si garantisce che Dispose sia chiamato indipendentemente dal flusso del codice, è
una buona idea assicurarsi che Dispose non Dispose mai un'eccezione quando si implementa
IDisposable . Altrimenti un'eccezione effettiva verrebbe sovrascritta dalla nuova eccezione che
risulterebbe in un incubo di debug.
A causa delle semantica di try..finally cui il using blocco traduce, il return economico funziona
https://riptutorial.com/it/home 910
come previsto - il valore di ritorno viene valutata prima finally viene eseguito blocco e il valore
disposto. L'ordine di valutazione è il seguente:
Tuttavia, non è possibile restituire la variabile disposable e disposable stessa, poiché essa
conterrebbe un riferimento disposto non valido - vedere l' esempio correlato .
È possibile utilizzare più nidificate using dichiarazioni senza aggiunta di più livelli di parentesi
nidificate. Per esempio:
Un'alternativa è scrivere:
Nota: le istruzioni nidificate using potrebbero attivare la regola CS2002 (vedere questa risposta per
chiarimenti) e generare un avviso. Come spiegato nella risposta collegata, è generalmente sicuro
annidare using istruzioni.
Quando i tipi all'interno dell'istruzione using sono dello stesso tipo, puoi separarli con virgole e
specificare il tipo una sola volta (sebbene questo sia raro):
Questo può essere utilizzato anche quando i tipi hanno una gerarchia condivisa:
https://riptutorial.com/it/home 911
La parola chiave var non può essere utilizzata nell'esempio precedente. Si verificherebbe un
errore di compilazione. Anche la dichiarazione separata da virgole non funzionerà quando le
variabili dichiarate hanno tipi di gerarchie diverse.
Questo sembra ok, ma il problema è che la valutazione delle espressioni LINQ è DBContext e
probabilmente verrà eseguita solo in un secondo momento, quando il DBContext sottostante è già
stato eliminato.
Quindi in breve l'espressione non viene valutata prima di lasciare l' using . Una possibile soluzione
a questo problema, il che rende ancora uso di using , è di indurre l'espressione di valutare
immediatamente chiamando un metodo che enumerare il risultato. Ad esempio ToList() ,
ToArray() , ecc. Se si utilizza la versione più recente di Entity Framework, è possibile utilizzare le
controparti async come ToListAsync() o ToArrayAsync() .
È importante notare, tuttavia, che chiamando ToList() o ToArray() , l'espressione verrà valutata
con entusiasmo, il che significa che tutte le persone con l'età specificata verranno caricate in
memoria anche se non si esegue iterazione su di esse.
https://riptutorial.com/it/home 912
Non è necessario controllare l'oggetto IDisposable per null . using non genererà un'eccezione e
Dispose() non verrà chiamato:
DisposableObject TryOpenFile()
{
return null;
}
if(disposable != null)
{
// here we are safe because disposable has been checked for null
disposable.DoSomething();
}
}
Gotcha: Eccezione nel metodo Dispose che maschera altri errori in Uso dei
blocchi
try
{
using (var disposable = new MyDisposable())
{
throw new Exception("Couldn't perform operation.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Vale la pena essere consapevoli di questa sottigliezza poiché potrebbe nascondere l'errore reale
che impediva la disposizione dell'oggetto e rendeva più difficile il debug.
https://riptutorial.com/it/home 913
La parola chiave using assicura che la risorsa definita all'interno dell'istruzione esista solo
nell'ambito dell'istruzione stessa. Qualsiasi risorsa definita all'interno dell'istruzione deve
implementare l'interfaccia IDisposable .
Tutti questi sono comunemente usati per accedere ai dati tramite C # e verranno comunemente
riscontrati durante la creazione di applicazioni incentrate sui dati. FooDataReader si può aspettare
che molte altre classi che non sono menzionate che implementano le stesse FooConnection ,
FooCommand , FooDataReader si comportino allo stesso modo.
https://riptutorial.com/it/home 914
using(var connection = new SqlConnection("{your-connection-string}"))
{
var query = "UPDATE YourTable SET Property = Value WHERE Foo = @foo";
using(var command = new SqlCommand(query,connection))
{
connection.Open();
Per alcuni casi d'uso, è possibile utilizzare la sintassi using per aiutare a definire un ambito
personalizzato. Ad esempio, è possibile definire la seguente classe per eseguire codice in una
cultura specifica.
È quindi possibile utilizzare questa classe per definire blocchi di codice che vengono eseguiti in
una cultura specifica.
https://riptutorial.com/it/home 915
using (new CultureContext("nl-NL"))
{
// Code in this block uses the "nl-NL" culture
Console.WriteLine(new DateTime(2016, 12, 25)); // Output: 25-12-2016 00:00:00
}
Nota: poiché non utilizziamo l'istanza di CultureContext che creiamo, non assegniamo una variabile
per questo.
Se si dispone di codice (una routine ) che si desidera eseguire in un contesto specifico (vincolo), è
possibile utilizzare l'iniezione della dipendenza.
L'esempio seguente mostra il vincolo di esecuzione in una connessione SSL aperta. Questa prima
parte sarà nella libreria o nel framework, che non esporrai al codice cliente.
if (!sslStream.IsAuthenticated)
{
throw new SecurityException("SSL tunnel not authenticated");
}
if (!sslStream.IsEncrypted)
{
throw new SecurityException("SSL tunnel not encrypted");
}
https://riptutorial.com/it/home 916
}
}
Ora il codice client che vuole fare qualcosa sotto SSL ma non vuole gestire tutti i dettagli SSL. Ora
puoi fare tutto ciò che vuoi all'interno del tunnel SSL, ad esempio scambiare una chiave
simmetrica:
SSLContext.ClientTunnel(tcpClient, this.ExchangeSymmetricKey);
Per fare ciò, è necessaria la clausola using() perché è l'unico modo (a parte un try..finally block)
che puoi garantire che il codice client ( ExchangeSymmetricKey ) non esca mai senza disporre
correttamente delle risorse usa e getta. Senza la clausola using() , non si potrebbe mai sapere se
una routine potrebbe rompere il vincolo del contesto per smaltire tali risorse.
https://riptutorial.com/it/home 917
Capitolo 162: Utilizzo di SQLite in C #
Examples
Creazione di CRUD semplice con SQLite in C #
Prima di tutto è necessario aggiungere il supporto SQLite alla nostra applicazione. Ci sono due
modi per farlo
• Scarica la DLL che soddisfa il tuo sistema dalla pagina di download di SQLite e quindi
aggiungi manualmente al progetto
• Aggiungi dipendenza SQLite tramite NuGet
https://riptutorial.com/it/home 918
L'installazione può essere eseguita anche dalla console di Gestione pacchetti con
Questo è tutto per il download, quindi possiamo andare direttamente nella programmazione.
Prima crea un semplice database SQLite con questa tabella e aggiungilo come un file al progetto
Inoltre, non dimenticare di impostare la proprietà Copia su Output Directory del file su Copia se
più recente di Copia sempre , in base alle proprie esigenze
https://riptutorial.com/it/home 919
Crea una classe chiamata User, che sarà l'entità di base per il nostro database
Scriveremo due metodi per l'esecuzione della query, il primo per l'inserimento, l'aggiornamento o
la rimozione dal database
return numberOfRowsAffected;
}
}
https://riptutorial.com/it/home 920
da.Dispose();
return dt;
}
}
}
Aggiungere utente
Modifica utente
Eliminazione dell'utente
https://riptutorial.com/it/home 921
};
Ottenere l'utente da Id
return user;
}
Nota : l'impostazione FailIfMissing su true crea il file data.db se mancante. Tuttavia, il file sarà
vuoto. Quindi, qualsiasi tabella richiesta deve essere ricreata.
https://riptutorial.com/it/home 922
c-sharp
https://riptutorial.com/it/home 923
Capitolo 163: Windows Communication
Foundation
introduzione
Windows Communication Foundation (WCF) è un framework per la creazione di applicazioni
orientate ai servizi. Utilizzando WCF, è possibile inviare dati come messaggi asincroni da un
endpoint di un servizio a un altro. Un endpoint del servizio può essere parte di un servizio
continuamente disponibile ospitato da IIS o può essere un servizio ospitato in un'applicazione. I
messaggi possono essere semplici come un singolo carattere o una parola inviata come XML o
complessa come un flusso di dati binari.
Examples
Iniziare campione
Il servizio descrive le operazioni che esegue in un contratto di servizio che espone pubblicamente
come metadati.
L'implementazione del servizio calcola e restituisce il risultato appropriato, come mostrato nel
seguente codice di esempio.
Il servizio espone un endpoint per la comunicazione con il servizio, definito utilizzando un file di
configurazione (Web.config), come mostrato nella seguente configurazione di esempio.
<services>
<service
name="StackOverflow.ServiceModel.Samples.CalculatorService"
behaviorConfiguration="CalculatorServiceBehavior">
<!-- ICalculator is exposed at the base address provided by
https://riptutorial.com/it/home 924
host: http://localhost/servicemodelsamples/service.svc. -->
<endpoint address=""
binding="wsHttpBinding"
contract="StackOverflow.ServiceModel.Samples.ICalculator" />
...
</service>
</services>
Il framework non espone i metadati per impostazione predefinita. In quanto tale, il servizio attiva
ServiceMetadataBehavior ed espone un endpoint MEX (metadata exchange) su http:
//localhost/servicemodelsamples/service.svc/mex . La seguente configurazione lo dimostra.
<system.serviceModel>
<services>
<service
name="StackOverflow.ServiceModel.Samples.CalculatorService"
behaviorConfiguration="CalculatorServiceBehavior">
...
<!-- the mex endpoint is explosed at
http://localhost/servicemodelsamples/service.svc/mex -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
Il client comunica utilizzando un determinato tipo di contratto utilizzando una classe client
generata da ServiceModel Metadata Utility Tool (Svcutil.exe).
Eseguire il seguente comando dal prompt dei comandi SDK nella directory del client per generare
il proxy digitato:
svcutil.exe /n:"http://StackOverflow.ServiceModel.Samples,StackOverflow.ServiceModel.Samples"
http://localhost/servicemodelsamples/service.svc/mex /out:generatedClient.cs
Come il servizio, il client utilizza un file di configurazione (App.config) per specificare l'endpoint
con il quale desidera comunicare. La configurazione dell'endpoint del client è costituita da un
indirizzo assoluto per l'endpoint del servizio, l'associazione e il contratto, come illustrato
nell'esempio seguente.
<client>
<endpoint
address="http://localhost/servicemodelsamples/service.svc"
https://riptutorial.com/it/home 925
binding="wsHttpBinding"
contract="StackOverflow.ServiceModel.Samples.ICalculator" />
</client>
L'implementazione client crea un'istanza del client e utilizza l'interfaccia tipizzata per iniziare a
comunicare con il servizio, come mostrato nel seguente codice di esempio.
// Create a client.
CalculatorClient client = new CalculatorClient();
https://riptutorial.com/it/home 926
Capitolo 164: XDocument e lo spazio dei
nomi System.Xml.Linq
Examples
Genera un documento XML
<FruitBasket xmlns="http://www.fruitauthority.fake">
<Fruit ID="F0001">
<FruitName>Banana</FruitName>
<FruitColor>Yellow</FruitColor>
</Fruit>
<Fruit ID="F0002">
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
Codice:
Per modificare un file XML con XDocument , devi caricare il file in una variabile di tipo XDocument ,
modificarlo in memoria, quindi salvarlo, sovrascrivendo il file originale. Un errore comune consiste
nel modificare l'XML in memoria e aspettarsi che il file sul disco cambi.
https://riptutorial.com/it/home 927
Dato un file XML:
// 1.
string xmlFilePath = "c:\\users\\public\\fruit.xml";
// 2.
XDocument xdoc = XDocument.Load(xmlFilePath);
// 3.
XNamespace ns = "http://www.fruitauthority.fake";
//4.
var elBanana = xdoc.Descendants()?.
Elements(ns + "FruitName")?.
Where(x => x.Value == "Banana")?.
Ancestors(ns + "Fruit");
// 5.
var elColor = elBanana.Elements(ns + "FruitColor").FirstOrDefault();
// 6.
if (elColor != null)
{
elColor.Value = "Brown";
}
// 7.
https://riptutorial.com/it/home 928
xdoc.Save(xmlFilePath);
Obbiettivo:
<FruitBasket xmlns="http://www.fruitauthority.fake">
<Fruit>
<FruitName>Banana</FruitName>
<FruitColor>Yellow</FruitColor>
</Fruit>
<Fruit>
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
Codice:
https://riptutorial.com/it/home 929
Capitolo 165: XmlDocument e lo spazio dei
nomi System.Xml
Examples
Interazione documento XML di base
// All XML documents must have one, and only one, root element
xml.AppendChild(root);
// Displays the XML document in the screen; optionally can be saved to a file
xml.Save(Console.Out);
}
<Sample>
<Account>
<One number="12"/>
<Two number="14"/>
</Account>
<Account>
<One number="14"/>
<Two number="16"/>
</Account>
https://riptutorial.com/it/home 930
</Sample>
using System.Xml;
using System.Collections.Generic;
1. Documento Xml
2. XDocument
3. XmlReader / XmlWriter
Prima di LINQ to XML eravamo usati XMLDocument per le manipolazioni in XML come
l'aggiunta di attributi, elementi e così via. Ora LINQ to XML utilizza XDocument per lo
stesso tipo di cose. Le sintassi sono molto più semplici di XMLDocument e richiedono
una quantità minima di codice.
XmlDocument
https://riptutorial.com/it/home 931
XmlDocument _doc = new XmlDocument();
_doc.Load(filename);
XDocument
Crea XmlDocument
XmlDocument
XDocument
/*result*/
<root name="value">
<child>"TextNode"</child>
</root>
XmlDocument
XDocument
https://riptutorial.com/it/home 932
XmlDocument
XDocument
Recupera il valore da tutti da tutti gli elementi figlio dove attributo = qualcosa.
XmlDocument
XDocument
Aggiungi un nodo
XmlDocument
XDocument
_doc.XPathSelectElement("ServerManagerSettings/TcpSocket").Add(new
XElement("SecondLevelNode"));
https://riptutorial.com/it/home 933
Titoli di coda
S.
Capitoli Contributors
No
https://riptutorial.com/it/home 934
Ahmed Khan, Mahmoud
Elgindy, Malick, Marcus
Höglund, Mateen Ulhaq,
Matt, Matt, Matt, Matt,
Michael B, Michael
Brandon Morris, Miljen
Mikic, Millan Sanchez,
Nate Barbettini, Nick,
Nick Cox, Nipun Tripathi,
NotMyself, Ojen,
PashaPash, pijemcolu,
Prateek, Raj Rao, Rajput
, Rakitić, Rion Williams,
RokumDev, RomCoo,
Ryan Hilbert, sebingel,
SeeuD1, solidcell,
Steven Ackley, sumit
sharma, Tofix, Tom
Bowers, Travis J, Tushar
patel, User 00000,
user3185569, Ven,
Victor Tomaili, viggity,
void, Wen Qin, Ziad Akiki
, Zze
ATechieThought,
ravindra, Rion Williams,
4 Accesso ai database
The_Outsider,
user2321864
Benjamin Hodgson,
dasblinkenlight, Dileep,
George Duckett,
just.another.programmer
, Matas Vaitkevicius,
5 Alberi di espressione matteeyah,
meJustAndrew, Nathan
Tuggy,
NikolayKondratyev, Rob,
Ruben Steins, Stephen
Leppik, Рахул Маквана
https://riptutorial.com/it/home 935
, Stephen Leppik
RamenChef, Sibeesh
Venu, Testing123,
9 Argomenti nominati e opzionali
The_Outsider, Tim
Yusupov
https://riptutorial.com/it/home 936
Webb, EJoshuaS,
EvilTak, gdyrrahitis,
George Duckett, Grimm
The Opiner, Guanxi,
guntbert, H. Pauwelyn,
jdpilgrim, ken2k, Kevin
Montrose, marshal craft,
Michael Richardson,
Moerwald, Nate
Barbettini, nickguletskii,
Pavel Mayorov, Pavel
Voronin, pinkfloydx33,
Rob, Serg Rogovtsev,
Stefano d'Antonio,
Stephen Leppik,
SynerCoder, trashr0x,
Tseng, user2321864,
Vincent
Alexander Mandt,
Andrew Diamond, Doruk,
LosManos, Lukas
13 attributi Kolletzki,
NikolayKondratyev,
Pavel Sapehin, SysVoid,
TKharaishvili
0xFF, bob0the0mighty,
17 C # 3.0 Caratteristiche FrenkyB, H. Pauwelyn,
ken2k, Maniero, Rob
Benjamin Hodgson,
Botond Balázs, H.
Pauwelyn, Proxima,
18 C # 4.0 Caratteristiche
Sibeesh Venu,
Squidward, Theodoros
Chatzigiannakis
https://riptutorial.com/it/home 937
Abob, alex.b, H.
19 C # 5.0 Caratteristiche
Pauwelyn
A_Arnold, Aaron
Anodide, Aaron Hudon,
Adil Mammadov, Adriano
Repetti, AER, AGB,
Akshay Anand, Alan
McBee, Alex Logan,
Amitay Stern,
anaximander, andre_ss6
, Andrea,
AndroidMechanic, Ares,
Arthur Rizzo, Ashwin
Ramaswami, avishayp,
Balagurunathan
Marimuthu, Bardia, Ben
Aaronson, Blubberguy22
, Bobson, bpoiss,
Bradley Uffner, Bret
Copeland, C4u, Callum
Watkins, Chad Levy,
Charlie H, ChrFin,
Community,
Conrad.Dean, Cyprien
20 C # 6.0 Caratteristiche
Autexier, Dan, Daniel
Minnaar, Daniel
Stradowski, DarkV1,
dasblinkenlight, David,
David G., David Pine,
Deepak gupta, DLeh,
dotctor, Durgpal Singh,
Ehsan Sajjad, el2iot2,
Emre Bolat, enrico.bacis,
Erik Schierboom,
fabriciorissetto, faso,
Franck Dernoncourt,
FrankerZ, Gabor
Kecskemeti, Gary, Gates
Wong, Geoff,
GingerHead, Gordon
Bell, Guillaume Pascal,
H. Pauwelyn, hankide,
Henrik H, iliketocode,
Iordanis , Irfan, Ivan
Yurchenko, J. Steen,
Jacob Linney, Jamie
https://riptutorial.com/it/home 938
Rees, Jason Sturges,
Jeppe Stig Nielsen, Jim,
JNYRanger, Joe, Joel
Etherton, John Slegers,
Johnbot, Jojodmo, Jonas
S, Juan, Kapep, ken2k,
Kit, Konamiman, Krikor
Ailanjian, Lafexlos, LaoR
, Lasse Vågsæther
Karlsen, M.kazem
Akhgary, Mafii, Magisch,
Makyen, MANISH
KUMAR CHOUDHARY,
Marc, MarcinJuraszek,
Mark Shevchenko,
Matas Vaitkevicius,
Mateen Ulhaq, Matt,
Matt, Matt, Matt Thomas,
Maximillian Laumeister,
mbrdev, Mellow, Michael
Mairegger, Michael
Richardson, Michał
Perłakowski, mike z,
Minhas Kamal, Mitch
Talmadge, Mohammad
Mirmostafa, Mr.Mindor,
mshsayem,
MuiBienCarlota, Nate
Barbettini, Nicholas Sizer
, nik, nollidge, Nuri
Tasdemir, Oliver Mellet,
Orlando William, Osama
AbuSitta, Panda, Parth
Patel, Patrick, Pavel
Voronin, PSN, qJake,
QoP, Racil Hilan,
Radouane ROUFID,
Rahul Nikate, Raidri,
Rajeev, Rakitić, ravindra,
rdans, Reeven, Richa
Garg, Richard, Rion
Williams, Rob, Robban,
Robert Columbia, Ryan
Hilbert, ryanyuyu, Sam,
Sam Axe, Samuel,
Sender, Shekhar, Shoe,
Slayther, solidcell,
https://riptutorial.com/it/home 939
Squidward, Squirrel,
stackptr, stark, Stilgar,
Sunny R Gupta, Suren
Srapyan, Sworgkh,
syb0rg, takrl, Tamir
Vered, Theodoros
Chatzigiannakis, Timothy
Shields, Tom Droste,
Travis J, Trent,
Trikaldarshi, Troyen,
Tushar patel, tzachs, Uri
Agassi, Uriil, uTeisT,
vcsjones, Ven, viggity,
Vishal Madhvani, Vlad,
Wai Ha Lee, Xiaoy312,
Yury Kerbitskov, Zano,
Ze Rubeus, Zimm1
https://riptutorial.com/it/home 940
mnoronha, MotKohn,
Name, Nate Barbettini,
Nico, Niek, nietras,
NikolayKondratyev, Nuri
Tasdemir, PashaPash,
Pavel Mayorov, PeteGO,
petrzjunior, Philippe,
Pratik, Priyank Gadhiya,
Pyritie, qJake, Raidri,
Rakitić, RamenChef,
Ray Vega, RBT, René
Vogt, Rob, samuelesque
, Squidward, Stavm,
Stefano, Stefano
d'Antonio, Stilgar, Tim
Pohlmann, Uriil,
user1304444,
user2321864,
user3185569, uTeisT,
Uwe Keim, Vlad, Vlad,
Wai Ha Lee, Wasabi Fan
, WerWet, wezten,
Wojciech Czerniak, Zze
mehrandvd, Squidward,
22 C # Script
Stephen Leppik
MCronin, The_Outsider,
25 Classi statiche
Xiaoy312
https://riptutorial.com/it/home 941
Come utilizzare C # Structs per creare un tipo Union DLeh, Milton Hernandez,
29
(simile a C Unions) Squidward, usr
codeape, Mark
33 Contesto di sincronizzazione in attesa asincrona Shevchenko,
RamenChef
https://riptutorial.com/it/home 942
Hommel, pinkfloydx33,
Robert Columbia,
RomCoo, Roy Dictus,
Sam, Saravanan Sachi,
Seph, Sklivvz,
The_Cthulhu_Kid, Tim
Medora, usr, Verena
Haunschmid, void,
Wouter, ZenLulz
glaubergft, MikeS159,
40 Crittografia (System.Security.Cryptography)
Ogglas, Pete
Adam, demonplus,
dotctor, Gavin Greenwalt
41 Cronometri
, Jeppe Stig Nielsen,
Sondre
Alexander Mandt,
Ameya Deshpande,
43 Dichiarazioni condizionali EJoshuaS, H. Pauwelyn,
Hayden, Kroltan,
RamenChef, Sklivvz
https://riptutorial.com/it/home 943
Kyle Trauberman, Martin
Zikmund, Matthew
Whited, Maxime, mbrdev
, Michael Mairegger,
MuiBienCarlota,
NikolayKondratyev,
Osama AbuSitta, PSGuy
, recursive, Richa Garg,
Richard, Rob, sdgfsdh,
Sergii Lischuk, Squirrel,
Stefano d'Antonio,
Tanner Swett, TarkaDaal
, Theodoros
Chatzigiannakis, vesi,
Wasabi Fan, Yanai
https://riptutorial.com/it/home 944
Vaitkevicius, Matt
Sherman, Michael
Mairegger, Michael
Richardson,
NotEnoughData, Oly,
RubberDuck, S.L. Barth,
Sunny R Gupta, Tagc,
Thriggle
BanksySan, Blachshma,
dbmuller, DJCubed,
Feelbad Soussi Wolfgun
51 File e streaming I / O DZ, intox, Mikko Viitala,
Sender, Squidward,
Tolga Evcimen, Wasabi
Fan
52 FileSystemWatcher Sondre
Theodoros
54 Func delegati Chatzigiannakis,
Valentin
https://riptutorial.com/it/home 945
Luke Ryan, Squidward,
Suren Srapyan
Bearington, Botond
Balázs, elibyy, Jonas S,
Osama AbuSitta,
65 guid
Sherantha, TarkaDaal,
The_Outsider, Tim
Ebenezer, void
https://riptutorial.com/it/home 946
Ben Aaronson, Benjamin
Hodgson, Bradley Uffner
, CalmBit, Cihan Yakar,
CodeWarrior, EyasSH,
Huseyin Durmus, Jasmin
Solanki, Jeppe Stig
Nielsen, Jon G, Jonas S,
Matt, NikolayKondratyev,
niksofteng, Rajput, Richa
Garg, Sam Farajpour
Ghamari, Shog9, Stu,
Thulani Chivandikwa,
trashr0x
68 IComparable alex
HappyCoding,
69 Identità ASP.NET
Skullomania
Aleks Andreev,
71 ILGenerator
thehennyy
https://riptutorial.com/it/home 947
76 Importa contatti Google 4444, Supraj v
Andrei, Kroltan,
LeopardSkinPillBoxHat,
79 Inizializzatori di oggetti
Marco, Nick DeVore,
Stephen Leppik
Blorgbeard, hatchet,
jaycer, Michael Sorens,
81 Inizializzazione delle proprietà
Parth Patel, Stephen
Leppik
https://riptutorial.com/it/home 948
OliPro007, Pavel
Mayorov, pinkfloydx33,
pyrocumulus,
RamenChef, Rob,
Thennarasan, Will Ray
Arjan Einbu,
ATechieThought, avs099
, bluray, Brendan L,
Dave Zych, DLeh, Ehsan
Sajjad, fabriciorissetto,
Guilherme de Jesus
87 Interpolazione a stringa Santos, H. Pauwelyn,
Jon Skeet, Nate
Barbettini, RamenChef,
Rion Williams,
Squidward, Stephen
Leppik, Tushar patel,
Wasabi Fan
https://riptutorial.com/it/home 949
fabriciorissetto, faso, flq,
George Duckett, Gilad
Naaman, Gudradain,
Jack, James Hughes,
Jamie Rees, John Meyer
, Jonesopolis,
MadddinTribleD,
Marimba, Matas
Vaitkevicius, Matt,
matteeyah, Mendhak,
Michael Bisbjerg, Nate
Barbettini, Nathaniel
Ford, nik0lias, niksofteng
, Oly, Pavel Pája Halbich
, Pavel Voronin, PMF,
Racil Hilan, raidensan,
Rasa , Robert Columbia,
RomCoo, Sam Hanley,
Scott Koland, Squidward
, Steve Dunn, Thulani
Chivandikwa, vesi
jaycer, NotEnoughData,
93 letterali
Racil Hilan
brijber, Christian
97 Linq to Objects Gollhardt, FortyTwo,
Kevin Green, Raphael
https://riptutorial.com/it/home 950
Pantaleão, Simon
Halsey, Tanveer Badar
Blachshma, Jon
100 Manipolazione delle stringhe Schneider, sferencik,
The_Outsider
AbdulRahman Ansari,
102 Metodi DateTime
C4u, Christian Gollhardt,
https://riptutorial.com/it/home 951
Felipe Oriani, Guilherme
de Jesus Santos, James
Hughes, Matas
Vaitkevicius,
midnightsyntax, Mostafiz
, Oluwafemi, Pavel
Yermalovich, Sondre,
theinarasu, Thulani
Chivandikwa
Aaron Hudon,
AbdulRahman Ansari,
Adi Lester, Adil
Mammadov, AGB,
AldoRomo88,
anaximander, Aphelion,
Ashwin Ramaswami,
ATechieThought, Ben
Aaronson, Benjol, binki,
Bjørn-Roger Kringsjå,
Blachshma, Blorgbeard,
Brett Veenstra, brijber,
Callum Watkins, Chad
McGrath, Charlie H,
Chris Akridge,
Chronocide,
CorrectorBot, cubrr,
Dan-Cook, Daniel
103 Metodi di estensione Stradowski, David G.,
David Pine, Deepak
gupta, diiN__________,
DLeh, Dmitry Bychenko,
DoNot, DWright, Ðаn,
Ehsan Sajjad, ekolis,
el2iot2, Elton,
enrico.bacis, Erik
Schierboom, ethorn10,
extremeboredom, Ezra,
fahadash, Federico
Allocati, Fernando
Matsumoto, FrankerZ,
gdziadkiewicz, Gilad
Naaman, GregC,
Gudradain, H. Pauwelyn,
HimBromBeere, Hsu Wei
Cheng, Icy Defiance,
Jamie Rees, Jeppe Stig
https://riptutorial.com/it/home 952
Nielsen, John Peters,
John Slegers, Jon
Erickson, Jonas S,
Jonesopolis, Kev, Kevin
Avignon, Kevin DiTraglia
, Kobi, Konamiman,
krillgar, Kurtis Beavers,
Kyle Trauberman,
Lafexlos, LMK, lothlarias,
Lukáš Lánský, Magisch,
Marc, MarcE, Marek
Musielak, Martin
Zikmund, Matas
Vaitkevicius, Matt, Matt
Dillard, Maximilian Ast,
mbrdev,
MDTech.us_MAN,
meJustAndrew, Michael
Benford, Michael
Freidgeim, Michael
Richardson, Michał
Perłakowski, Nate
Barbettini, Nick Larsen,
Nico, Nisarg Shah, Nuri
Tasdemir, Parth Patel,
pinkfloydx33, PMF,
Prashanth Benny, QoP,
Raidri, Reddy, Reeven,
Ricardo Amores, Richard
, Rion Williams, Rob,
Robert Columbia, Ryan
Hilbert, ryanyuyu, S. Tar
ık Çetin, Sam Axe, Shoe
, Sibeesh Venu, solidcell
, Sondre, Squidward,
Steven, styfle, SysVoid,
Tanner Swett, Timothy
Rascher, TKharaishvili,
T-moty, Tobbe, Tushar
patel, unarist,
user3185569, user40521
, Ven, Victor Tomaili,
viggity
https://riptutorial.com/it/home 953
Mark Shevchenko, Parth
Patel, PedroSouki,
Pierre Theate, Sondre,
Tushar patel
Botond Balázs, H.
Pauwelyn, hatcyl, John,
107 Modificatori di accesso Justin Rohr, Kobi, Robert
Woods, Thaoden,
ZenLulz
Benjamin Hodgson,
Braydie, DmitryG,
Gordon Bell, Jasmin
Solanki, Jon Schneider,
Konstantin Vdovkin,
110 Nullable types
Maximilian Ast, Mikko
Viitala, Nicholas Sizer,
Patrick Hofman, Pavel
Mayorov, pinkfloydx33,
Vitaliy Fedorchenko
4444, Agramer,
Ashutosh, krimog, Kyle
Trauberman, Mathias
111 NullReferenceException Müller, Philip C,
RamenChef, S.L. Barth,
Shelby115, Squidward,
vicky, Zikato
https://riptutorial.com/it/home 954
Jonathan Anctil,
MuiBienCarlota
aashishkoirala, Ankit
Rana, Aristos, Bradley
Uffner, David Arno,
David G., David Pine,
demonplus, Denis
Elkhov, Diligent Key
Presser, Eamon Charles,
Ehsan Sajjad,
eouw0o83hf, Fernando
115 Operatore Null Coalescing
Matsumoto, H. Pauwelyn
, Jodrell, Jon Schneider,
Jonesopolis, Martin
Zikmund, Mike C, Nate
Barbettini, Nic Foster,
petelids, Prateek, Rahul
Nikate, Rion Williams,
Rob, smead, tonirush,
Wasabi Fan, Will Ray
https://riptutorial.com/it/home 955
Mohamed Belal, Nate
Barbettini, Nico, Oly,
pascalhein, Pavel
Voronin, petelids, Philip
C, Racil Hilan, RhysO,
Robert Columbia,
Rodolfo Fadino Junior,
Sachin Joseph, Sam,
slawekwin, slinzerthegod
, Squidward, Testing123,
TyCobb, Wasabi Fan,
Xiaoy312, Zaheer Ul
Hassan
Austin T French,
Blachshma, bluish,
CharithJ, Chief Wiggum,
cyberj0g, Daryl, deloreyk
, jaycer, Jaydip Jadhav,
Jon G, Jon Schneider,
118 Operazioni stringhe comuni
juergen d, Konamiman,
Maniero, Paul Weiland,
Racil Hilan, RoelF,
Stefan Steiger, Steven,
The_Outsider, tiedied61,
un-lucky, WizardOfMenlo
https://riptutorial.com/it/home 956
Roncaglia, just.ru,
Karthik AMR, Mark
Shevchenko, Michael
Richardson,
MuiBienCarlota, Myster,
Nate Barbettini, Noctis,
Nuri Tasdemir, Olivier
De Meulder, OP313,
ravindra, Ricardo
Amores, Rion Williams,
rocky, Sompom, Tot
Zam, un-lucky, Vlad,
void, Wasabi Fan,
Xiaoy312, ZenLulz
https://riptutorial.com/it/home 957
Ehsan Sajjad, EJoshuaS
, Elad Lachmi, Eric
Lippert, EvenPrime, F_V,
Felix, fernacolo,
Fernando Matsumoto,
forsvarir, Francis Lord,
Gavin Greenwalt, gdoron
, George Duckett, Gilad
Naaman, goric, greatwolf
, H. Pauwelyn,
Happypig375, Icemanind
, Jack, Jacob Linney,
Jake, James Hughes,
Jcoffman, Jeppe Stig
Nielsen, jHilscher, João
Lourenço, John Slegers,
JohnD, Jon Schneider,
Jon Skeet,
JoshuaBehrens, Kilazur,
Kimmax, Kirk Woll, Kit,
Kjartan, kjhf, Konamiman
, Kyle Trauberman,
kyurthich, levininja,
lokusking, Mafii, Mamta
D, Mango Wong, MarcE,
MarcinJuraszek, Marco
Scabbiolo, Martin, Martin
Klinke, Martin Zikmund,
Matas Vaitkevicius,
Mateen Ulhaq, Matěj
Pokorný, Mat's Mug,
Matthew Whited, Max,
Maximilian Ast, Medeni
Baykal, Michael
Mairegger, Michael
Richardson, Michel
Keijzers, Mihail Shishkov
, mike z, Mr.Mindor,
Myster, Nicholas Sizer,
Nicholaus Lawson, Nick
Cox, Nico, nik,
niksofteng,
NotEnoughData,
numaroth, Nuri Tasdemir
, pascalhein, Pavel
Mayorov, Pavel Pája
Halbich, Pavel
https://riptutorial.com/it/home 958
Yermalovich, Pavieł
Kraskoŭski, Paweł Mach,
petelids, Peter Gordon,
Peter L., PMF, Rakitić,
RamenChef, ranieuwe,
Razan, RBT, Renan
Gemignani, Ringil, Rion
Williams, Rob, Robert
Columbia, ro
binmckenzie, RobSiklos,
Romain Vincent,
RomCoo, ryanyuyu, Sain
Pradeep, Sam, Sándor
Mátyás Márton, Sanjay
Radadiya, Scott,
sebingel, Skipper,
Sobieck, sohnryang,
somebody, Sondre,
Squidward, Stephen
Leppik, Sujay Sarma,
Suyash Kumar Singh,
svick, TarkaDaal,
th1rdey3, Thaoden,
Theodoros
Chatzigiannakis,
Thorsten Dittmar, Tim
Ebenezer, titol, tonirush,
topolm, Tot Zam,
user3185569, Valentin,
vcsjones, void, Wasabi
Fan, Wavum,
Woodchipper,
Xandrmoro, Zaheer Ul
Hassan, Zalomon, Zohar
Peled
https://riptutorial.com/it/home 959
125 Programmazione orientata agli oggetti in C # Yashar Aliabasi
https://riptutorial.com/it/home 960
Ellis-Jones, jao,
jiaweizhang, Jodrell, Jon
Bates, Jon G, Jon
Schneider, Jonas S,
karaken12, KevinM,
Koopakiller, leppie, LINQ
, Lohitha Palagiri,
ltiveron, Mafii, Martin
Zikmund, Matas
Vaitkevicius, Mateen
Ulhaq, Matt, Maxime,
mburleigh, Meloviz,
Mikko Viitala,
Mohammad Dehghan,
mok, Nate Barbettini,
Neel, Neha Jain, Néstor
Sánchez A., Nico, Noctis
, Pavel Mayorov, Pavel
Yermalovich, Paweł
Hemperek, Pedro, Phuc
Nguyen, pinkfloydx33,
przno, qJake, Racil Hilan
, rdans, Rémi, Rion
Williams, rjdevereux,
RobPethi, Ryan Abbott,
S. Rangeley, S.Akbari,
S.L. Barth, Salvador
Rubio Martinez, Sanjay
Radadiya, Satish Yadav,
sebingel, Sergio
Domínguez, SilentCoder,
Sivanantham Padikkasu,
slawekwin, Sondre,
Squidward, Stephen
Leppik, Steve Trout,
Tamir Vered, techspider,
teo van kot, th1rdey3,
Theodoros
Chatzigiannakis, Tim Iles
, Tim S. Van Haren,
Tobbe, Tom, Travis J,
tungns304, Tushar patel,
user1304444,
user3185569, Valentin,
varocarbas, VictorB,
Vitaliy Fedorchenko,
vivek nuna, void, wali,
https://riptutorial.com/it/home 961
wertzui, WMios,
Xiaoy312, Yaakov Ellis,
Zev Spitz
https://riptutorial.com/it/home 962
Stephen Leppik,
TorbenJ
Artificial Stupidity,
136 Runtime Compile
Stephen Leppik, Tommy
Danny Bogers,
jlawcordova, Jon
137 ruscello
Schneider, Nuri
Tasdemir, Pushpendra
David, Maxim,
140 Serializzazione binaria RamenChef, Stephen
Leppik
https://riptutorial.com/it/home 963
Solanki, Marek Musielak,
Mark Shevchenko,
Matas Vaitkevicius,
Mendhak, MGB, nikchi,
Philip C, Rahul Nikate,
Raidri, RamenChef,
Richard, Richard, Rion
Williams, ryanyuyu, teo
van kot, Vincent, void,
Wyck
ATechieThought, brijber,
Jeremy Kato, Jon
144 StringBuilder
Schneider, Robert
Columbia, The_Outsider
Benjamin Hodgson,
Brandon, Collin Stevens,
149 Task Libreria parallela
i3arnon, Mokhtar Ashour
, Murtuza Vohra
https://riptutorial.com/it/home 964
Aaron Hudon, Alexander
Petrov, Austin T French,
captainjamie, Eldar
Dordzhiev, H. Pauwelyn,
150 threading ionmike, Jacob Linney,
JohnLBevan,
leondepdelaw, Mamta D,
Matthijs Wessels, Mellow
, RamenChef, Zoba
Fernando Matsumoto,
152 Tipi anonimi
goric, Stephen Leppik
Community, connor,
154 Tipo di conversione
Ehsan Sajjad, Lijo
Daryl, David, H.
Pauwelyn, Kilazur, Mark
156 Tipo dinamico
Shevchenko, Nate
Barbettini, Rob
Alexey, BanksySan,
157 Uguale e GetHashCode hatcyl, ja72, Jeppe Stig
Nielsen, meJustAndrew,
https://riptutorial.com/it/home 965
Rob, scher, Timitry,
viggity
Fernando Matsumoto,
Jesse Williams,
JohnLBevan, Kit,
159 Uso della direttiva
Michael Freidgeim, Nuri
Tasdemir, RamenChef,
Tot Zam
Aleks Andreev,
160 Utilizzando json.net
Snipzwolf
Adam Houldsworth,
Ahmar, Akshay Anand,
Alex Wiese, andre_ss6,
Aphelion, Benjol, Boris
Callens, Bradley
Grainger, Bradley Uffner,
bubbleking, Chris Marisic
, ChrisWue, Cristian T,
cubrr, Dan Ling, Danny
Chen, dav_i, David
Stockinger, dazerdude,
Denis Elkhov, Dmitry
161 Utilizzando la dichiarazione
Bychenko, Erik
Schierboom, Florian
Greinacher, gdoron, H.
Pauwelyn, Herbstein,
Jon Schneider, Jon
Skeet, Jonesopolis, JT.,
Ken Keenan, Kev, Kobi,
Kyle Trauberman, Lasse
Vågsæther Karlsen,
LegionMammal978,
Lorentz Vedeler, Martin,
Martin Zikmund, Maxime
https://riptutorial.com/it/home 966
, Nuri Tasdemir, Peter K,
Philip C, pid, René Vogt,
Rion Williams, Ryan
Abbott, Scott Koland,
Sean, Sparrow, styfle,
Sunny R Gupta,
Sworgkh, Thaoden,
The_Cthulhu_Kid, Tom
Droste, Tot Zam, Zaheer
Ul Hassan
Carmine,
162 Utilizzo di SQLite in C # NikolayKondratyev,
th1rdey3, Tim Yusupov
Crowcoder, Jon
164 XDocument e lo spazio dei nomi System.Xml.Linq
Schneider
https://riptutorial.com/it/home 967