990 likes | 1.19k Vues
Introduzione a C#. Carlo Becchi carlo.becchi@iol.it. C#: Strumento Principe per .net. Primo linguaggio orientato alle componenti della famiglia C/C++ Tutto è DAVVERO un oggetto Unisce potenza, semplicità e chiarezza di C++, Java, VB… Completamente nuovo, non ha vincoli con il passato.
E N D
Introduzione a C# Carlo Becchicarlo.becchi@iol.it
C#: Strumento Principe per .net • Primo linguaggio orientato alle componenti della famiglia C/C++ • Tutto è DAVVERO un oggetto • Unisce potenza, semplicità e chiarezza di C++, Java, VB… • Completamente nuovo, non ha vincoli con il passato
C#: Strumento Principe per .net • Indipendente dalla piattaforma e scalabile • “Nato con” e “cucito addosso” al .NET Framework • Può essere integrato nelle pagine web • Completamente Type Safe
C#: Strumento Principe per .net • Standardizzato dall’ECMA • Ideato da AndersHejlsberg e dal team di J++
Tutto è un oggetto • In C# tutti i tipi reference, sono derivati dal tipo base System.Object. • Ogni oggetto eredita i metodi base da System.Object … ma proprio OGNI* tipo… *Mediante il meccanismo di Boxing
Tutto è un oggetto using System; class Test { static void Main() { Console.WriteLine(3.ToString()); } } ToString restituisce una stinga che rappresenta il valore dell’oggetto
Tutto è un oggetto In particolare la classe System.Object offre i seguenti metodi: Equals (public, virtual): Permette la comparazione di due oggetti per stabilire se il loro valore è uguale. GetHashCode (public, virtual): Permette ai tipi di restituire un integer a 32bit con segno come codice hash per i suoi oggetti. Si solito viene utilizzato per memorizzare oggetti in una tabella hash. ToString (public, virtual): Permette ad un tipo di fornire in ritorno una stringa che rappresenta il valore dell’oggetto. GetType (public, non-virtual): Restituisce un oggetto che rappresenta il tipo dell’oggetto. MemberwiseClone (protected, non-virtual): Permette al tipo di costruire una nuova istanza che è copia di se stesso. Finalize (protected, virtual): Permette di ripulire dalla memoria gli oggetti del tipo e rilasciare le risorse associate.
Tutto è un oggetto Output 1 System.Int32 1 using System; public class MyClass { public static void Main() { object a; a = 1; // un esempio di boxing Console.WriteLine(a); Console.WriteLine(a.GetType()); Console.WriteLine(a.ToString()); Console.WriteLine(); } }
Hello, World! • Si utilizza il metodo WriteLine della classe Console, presente nel namespace System contenuto nell’assembly mscorlib.dll. • Salutiamo il mondo in C#, VB e C++
Hello, World: C# // Permette riferimenti semplificati al namespace System using System; // Questa classe esiste solo per ospitare la funzione entry point dell'applicazione class MainApp { // Il metodo statico Main è l'entry point dell'applicazione public static void Main() { // Scrive il testo sulla console Console.WriteLine("Hello World using C#!"); } }
Hello, World: VB ' Permette riferimenti semplificati al namespace System Imports System ' Il Module ospita l'entry point dell'applicazione Public Module modmain ' "Main" è l'entry point dell'applicazione Sub Main() ' Scrive il testo sulla console Console.WriteLine ("Hello World using Visual Basic!") End Sub End Module
Hello, World: C++ // L'utilizzo dell'assemby mscorlib.dll deve essere specificato! #using <mscorlib.dll> // Permette riferimenti semplificati al namespace System using namespace System; // La global function "main" è l'entry point dell'applicazione void main() { // Scrive il testo sulla console Console::WriteLine("Hello World using Managed Extensions for C++!"); }
Sviluppo Cross Language • L’interoperabilità tra linguaggi aderenti al CLS è immediata • Da una classe base scritta in C++ ne sarà derivata una in VB, dalla quale ne sarà derivata una in IL e da C#…
VCBase.cpp #using <mscorlib.dll> using namespace System; public class VCBase { protected: VCBase(){ Console::WriteLine(" Executing the VCBase::VCBase() constructor"); } public: virtual void Method() = 0; void MethodThatThrows(){ throw(new OutOfMemoryException("We are out of some resource!")); } };
VBDerived.vb Option Explicit On Option Strict On Imports System Public Class VBDerived Inherits VCBase Public Sub New() Console.WriteLine(" Executing the VBDerived.New() constructor") End Sub Overrides Public Sub Method Console.WriteLine(" Executing the VBDerived.Method() virtual method") End Sub End Class
ILDerived.il .module extern VBDerived.netmodule .class public auto ansi ILDerived extends [.module VBDerived.netmodule]VBDerived { .method public specialname rtspecialname instance void .ctor() il managed { .maxstack 1 .locals init (class System.Object[] V_0) IL_0000: ldarg.0 IL_0001: call instance void [.module VBDerived.netmodule]VBDerived::.ctor() IL_0006: ldstr " Executing the ILDerived::ctor() constructor" IL_000b: call void [mscorlib]System.Console::WriteLine(class System.String) IL_0010: ret } .method public virtual instance void Method() il managed { .maxstack 1 .locals init (class System.Object[] V_0) IL_0000: ldstr " Executing the ILDerived::Method() virtual method" IL_0005: call void [mscorlib]System.Console::WriteLine(class System.String) IL_000a: ret } }
CSDerived.cs using System; public class CSDerived:ILDerived{ public CSDerived(){ Console.WriteLine("Executing the CSDerived.CSDerived() constructor"); } override public void Method(){ Console.WriteLine(" Executing the CSDerived.Method() virtual method"); } }
class App{ public static void Main(){ CrossObj(); } static void CrossObj(){ // Crea un array di oggetti per immagazzinare quelli definiti //negli altri linguaggi VCBase[] objects = new VCBase[3]; // Carica nella posizione 0 dell'array l'oggetto //creato usando IL Console.WriteLine("\nCreating object: ILDerived"); objects[0] = new ILDerived(); // Carica nella posizione 1 dell'array l'oggetto //creato usando C# Console.WriteLine("\nCreating object: CSDerived"); objects[1] = new CSDerived(); // Carica nella posizione 2 dell'array l'oggetto //creato usando VB Console.WriteLine("\nCreating object: VBDerived"); objects[2] = new VBDerived(); // Chiama il metodo virtuale di ogni oggetto Console.WriteLine("\nCalling Methods"); foreach(VCBase obj in objects){ obj.Method(); } } } CrossLang.cs
Boxing ed Unboxing dei Value • Il Boxing dei value è un concetto essenziale nel sistema dei tipi del C#. Con il boxing e l’unboxing si può realizzare un collegamento tra i value type e i reference type permettendo che il valore di un value type sia convertito da e verso un oggetto. • Convertire un value type in un reference type è detto Boxing, il processo inverso Unboxing. • Il Boxing avviene automaticamente quando un value type è utilizzato in una locazione che richiederebbe l’uso di un oggetto. Il Boxing di un value type consiste nell’allocare l’istanza di un oggetto e copiare il valore nell’istanza.
Boxing ed Unboxing dei Value using System; class Test { static void Main() { int i = 1; object o = i; // boxing // verifica che o sia davvero un int if (o is int) { Console.Write("O is an int"); } int j = (int) o; // unboxing } }
Boxing ed Unboxing dei Value using System; public class UnboxingTest { public static void Main() { int intI = 123; object o = intI; // Riferimenti a oggetti incompatibili producono // InvalidCastException try { int intJ = (short) o; Console.WriteLine("Unboxing OK."); } catch (InvalidCastException e) { Console.WriteLine("{0} Error: Incorrect unboxing.",e); } } } Boxing Scorretto: Errore di Runtime
Differenze tra Value e Reference Type • Reference Type allocati nel Managed Heap, l’operatore restituisce l’indirizzo di memoria dell’oggetto (GC) • Value Type allocati nello stack del thread, la variabile che rappresenta l’oggetto ne contiene direttamente il valore (nessuna GC)
Differenze tra Value e Reference Type using System; // E' un tipo Reference (a causa del 'class') class RefType { public int x; } // E' un tipo Value (a causa del 'struct') struct ValType { public int x; } class App { static void Main() { RefType rt1 = new RefType(); // Allocato nell'heap ValType vt1 = new ValType(); // Allocato nello stack rt1.x = 10; // Cambia il riferimento a cui punta vt1.x = 10; // Cambiato il valore nello stack RefType rt2 = rt1; // Copia il solo puntatore ValType vt2 = vt1; // Alloca nello stack e copia i membri rt1.x = 20; vt1.x = 20; Console.WriteLine("rt1.x = {0}, rt2.x = {1}", rt1.x, rt2.x); Console.WriteLine("vt1.x = {0}, vt2.x = {1}", vt1.x, vt2.x); Console.Write("Press Enter to close window..."); Console.Read(); } }
Differenze tra Value e Reference Type RefType rt1 = new RefType(); ValType vt1 = new ValType(); rt1.x = 10; vt1.x = 10; RefType rt2 = rt1; ValType vt2 = vt1; rt1.x = 20; vt1.x = 20; rt1.x 10 vt1.x 10 rt2.x vt2.x 10 rt1.x 20 rt2.x vt1.x 20
Delegate • Un oggetto delegate contiene informazioni necessarie a richiamare uno specifico metodo di un dato oggetto. • Corrispondente “Type Safe” e Object oriented del Function Pointer • Permettono l’esecuzione dei Callback in maniera sicura • Sono definiti in runtime e si riferiscono solo a metodi e non ad una intera classe.
Delegate • Un istanza di un delegate incapsula uno o più metodi, ognuno noto come callable entity. • L’oggetto delegate può essere passato al codice che richiama il metodo in esso incapsulato senza sapere in compile time quale metodo sarà invocato. • L’unica cosa che richiede al metodo che incapsula è di essere compatibile con il tipo del delegate
Delegate Dichiarazione delegate void SimpleDelegate(); class Test { static void A() { System.Console.WriteLine("Test.A"); } static void Main() { SimpleDelegate d = new SimpleDelegate(A); d(); } }
Delegate void MultiCall(SimpleDelegate d, int count) { for (int i = 0; i < count; i++) d(); } } • Il metodo Multicall non considera il tipo del metodo di destinazione per il delegate SimpleDelegate, la sua accessibilità o il fatto che esso sia o meno statico. Tutto ciò che importa che sia compatibile con SimpleDelegate
class DChatServer { public delegate void OnMsgArrived(String message); private static OnMsgArrived onMsgArrived; private DChatServer() {} public static void ClientConnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Combine(DChatServer.onMsgArrived, onMsgArrived); } public static void ClientDisconnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Remove(DChatServer.onMsgArrived, onMsgArrived); } public static void SendMsg(String msg) { // Invia un messaggio a TUTTI i client SendMsg(msg, null); } public static void SendMsg(String msg, Object excludeClient) { // Invia un messaggio a tutti i client tranne 'excludeClient' if (excludeClient == null) { onMsgArrived(msg); } else { Delegate[] DelegateList = onMsgArrived.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != excludeClient) { ((OnMsgArrived) DelegateList[i])(msg); } } } } }
class DChatClient { private void onMsgArrived(String msg) { Console.WriteLine("Msg arrived (Client {0}): {1}", clientName, msg); } private String clientName; public DChatClient(String clientName) { this.clientName = clientName; DChatServer.ClientConnect(new DChatServer.OnMsgArrived(onMsgArrived)); } public void Dispose() { DChatServer.ClientDisconnect(new DChatServer.OnMsgArrived(onMsgArrived)); GC.SuppressFinalize(this); } ~DChatClient() { Dispose(); } }
private static void DelegateChatServerDemo() { Console.WriteLine("Demo start: Delegate Chat Server."); DChatClient cc1 = new DChatClient("1"); DChatClient cc2 = new DChatClient("2"); DChatClient cc3 = new DChatClient("3"); DChatServer.SendMsg("Hi to all clients"); DChatServer.SendMsg("Hi to all clients except client 2", cc2); // Sconnette esplicitamente i client dal chat server. // Se questo non viene fatto, la memoria dei client potrebbe // non essere liberata finché il server attivo, ovvero fino // alla chiusura dell'applicazione cc1.Dispose(); cc2.Dispose(); cc3.Dispose(); Console.WriteLine("Demo stop: Delegate Chat Server."); }
class DChatServer { public delegate void OnMsgArrived(String message); private static OnMsgArrived onMsgArrived; private DChatServer() {} public static void ClientConnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Combine(DChatServer.onMsgArrived, onMsgArrived); } public static void ClientDisconnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Remove(DChatServer.onMsgArrived, onMsgArrived); } public static void SendMsg(String msg) { // Invia un messaggio a TUTTI i client SendMsg(msg, null); } public static void SendMsg(String msg, Object excludeClient) { // Invia un messaggio a tutti i client tranne 'excludeClient' if (excludeClient == null) { onMsgArrived(msg); } else { Delegate[] DelegateList = onMsgArrived.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != excludeClient) { ((OnMsgArrived) DelegateList[i])(msg); } } } } }
private static void DelegateChatServerDemo() { Console.WriteLine("Demo start: Delegate Chat Server."); DChatClient cc1 = new DChatClient("1"); DChatClient cc2 = new DChatClient("2"); DChatClient cc3 = new DChatClient("3"); DChatServer.SendMsg("Hi to all clients"); DChatServer.SendMsg("Hi to all clients except client 2", cc2); // Sconnette esplicitamente i client dal chat server. // Se questo non viene fatto, la memoria dei client potrebbe // non essere liberata finché il server attivo, ovvero fino // alla chiusura dell'applicazione cc1.Dispose(); cc2.Dispose(); cc3.Dispose(); Console.WriteLine("Demo stop: Delegate Chat Server."); }
class DChatClient { private void onMsgArrived(String msg) { Console.WriteLine("Msg arrived (Client {0}): {1}", clientName, msg); } private String clientName; public DChatClient(String clientName) { this.clientName = clientName; DChatServer.ClientConnect(new DChatServer.OnMsgArrived(onMsgArrived)); } public void Dispose() { DChatServer.ClientDisconnect(new DChatServer.OnMsgArrived(onMsgArrived)); GC.SuppressFinalize(this); } ~DChatClient() { Dispose(); } }
class DChatServer { public delegate void OnMsgArrived(String message); private static OnMsgArrived onMsgArrived; private DChatServer() {} public static void ClientConnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Combine(DChatServer.onMsgArrived, onMsgArrived); } public static void ClientDisconnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Remove(DChatServer.onMsgArrived, onMsgArrived); } public static void SendMsg(String msg) { // Invia un messaggio a TUTTI i client SendMsg(msg, null); } public static void SendMsg(String msg, Object excludeClient) { // Invia un messaggio a tutti i client tranne 'excludeClient' if (excludeClient == null) { onMsgArrived(msg); } else { Delegate[] DelegateList = onMsgArrived.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != excludeClient) { ((OnMsgArrived) DelegateList[i])(msg); } } } } }
private static void DelegateChatServerDemo() { Console.WriteLine("Demo start: Delegate Chat Server."); DChatClient cc1 = new DChatClient("1"); DChatClient cc2 = new DChatClient("2"); DChatClient cc3 = new DChatClient("3"); DChatServer.SendMsg("Hi to all clients"); DChatServer.SendMsg("Hi to all clients except client 2", cc2); // Sconnette esplicitamente i client dal chat server. // Se questo non viene fatto, la memoria dei client potrebbe // non essere liberata finché il server attivo, ovvero fino // alla chiusura dell'applicazione cc1.Dispose(); cc2.Dispose(); cc3.Dispose(); Console.WriteLine("Demo stop: Delegate Chat Server."); }
class DChatServer { public delegate void OnMsgArrived(String message); private static OnMsgArrived onMsgArrived; private DChatServer() {} public static void ClientConnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Combine(DChatServer.onMsgArrived, onMsgArrived); } public static void ClientDisconnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Remove(DChatServer.onMsgArrived, onMsgArrived); } public static void SendMsg(String msg) { // Invia un messaggio a TUTTI i client SendMsg(msg, null); } public static void SendMsg(String msg, Object excludeClient) { // Invia un messaggio a tutti i client tranne 'excludeClient' if (excludeClient == null) { onMsgArrived(msg); } else { Delegate[] DelegateList = onMsgArrived.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != excludeClient) { ((OnMsgArrived) DelegateList[i])(msg); } } } } }
private static void DelegateChatServerDemo() { Console.WriteLine("Demo start: Delegate Chat Server."); DChatClient cc1 = new DChatClient("1"); DChatClient cc2 = new DChatClient("2"); DChatClient cc3 = new DChatClient("3"); DChatServer.SendMsg("Hi to all clients"); DChatServer.SendMsg("Hi to all clients except client 2", cc2); // Sconnette esplicitamente i client dal chat server. // Se questo non viene fatto, la memoria dei client potrebbe // non essere liberata finché il server attivo, ovvero fino // alla chiusura dell'applicazione cc1.Dispose(); cc2.Dispose(); cc3.Dispose(); Console.WriteLine("Demo stop: Delegate Chat Server."); }
class DChatClient { private void onMsgArrived(String msg) { Console.WriteLine("Msg arrived (Client {0}): {1}", clientName, msg); } private String clientName; public DChatClient(String clientName) { this.clientName = clientName; DChatServer.ClientConnect(new DChatServer.OnMsgArrived(onMsgArrived)); } public void Dispose() { DChatServer.ClientDisconnect(new DChatServer.OnMsgArrived(onMsgArrived)); GC.SuppressFinalize(this); } ~DChatClient() { Dispose(); } }
class DChatServer { public delegate void OnMsgArrived(String message); private static OnMsgArrived onMsgArrived; private DChatServer() {} public static void ClientConnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Combine(DChatServer.onMsgArrived, onMsgArrived); } public static void ClientDisconnect(OnMsgArrived onMsgArrived) { DChatServer.onMsgArrived = (OnMsgArrived) Delegate.Remove(DChatServer.onMsgArrived, onMsgArrived); } public static void SendMsg(String msg) { // Invia un messaggio a TUTTI i client SendMsg(msg, null); } public static void SendMsg(String msg, Object excludeClient) { // Invia un messaggio a tutti i client tranne 'excludeClient' if (excludeClient == null) { onMsgArrived(msg); } else { Delegate[] DelegateList = onMsgArrived.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != excludeClient) { ((OnMsgArrived) DelegateList[i])(msg); } } } } }