Sviluppo Cross Language | ||
Differenze tra Value e Reference Type |
In questo esempio si vuole mettere in evidenza uno degli aspetti più interessanti della piattaforma .NET, ovvero l'estrema facilità di utilizzo di più linguaggi di programmazione nel contesto di un unico progetto. Saranno creati due assembly: il primo è una libreria di tipo DLL che definisce una semplice classe di base scritta con le estensioni gestite (managed extension) per C++; il secondo assembly è un eseguibile che definisce tre classi derivate scritte rispettivamente in C#, Visual Basic e in Intermediate Language. Questi tipi derivano l'uno dall'altro e infine dalla classe di base in managed C++. Per concludere l'eseguibile crea istanze di ognuno dei tipi derivati e chiama un metodo virtuale per uno. Questo esempio è puramente didattico e fortemente semplificato, ma fornisce un'idea di come .NET Framework sia un ambiente dove molti sviluppatori possono lavorare insieme indipendentemente dal linguaggio di programmazione scelto. VCBase.cpp #using mscorlib.dll using namespace System; __gc 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!")); } }; Questo codice crea una semplice classe di base scritta in C++, gli altri moduli creeranno classi derivate da questa, ma saranno scritti in Visual Basic, C# e IL. Le considerazioni sull'assembly mscorlib.dll sono identiche a quelle viste nell'esempio precedente (hello world!). .NET Framework, offre una funzione di Garbage Collection (GC), che facilita lo sviluppo abilitando l'ambiente a tener traccia delle risorse, come gli oggetti, ed automaticamente rilasciarle quando non sono più necessarie. La keyword __gc nella dichiarazione della classe VCBase marca la classe come "gestita", permettendo questo meccanismo. Una scritta su console (" Executing the VCBase::VCBase() constructor") avvisa quando è creata una istanza della classe VCBase (constructor). Il metodo Method non fa nulla, ma non serve perchè verrà subito scavalcato da un Method da esso derivato nella classe in Visual Basic. Piuttosto che un throw esplicito, quello finale agisce in caso in cui il codice acceda a risorse non disponibili. VBDerived.vb Option Explicit On Option Strict On Imports System Public Class VBDerived Inherits VCBase Public Sub New() REM MyBase.New Console.WriteLine(" Executing the VBDerived.New() constructor") End Sub Overrides Public Sub Method Console.WriteLine(" Executing the VBDerived.Method() virtual method") End Sub Public Sub AnotherMethodThatThrows Try MyBase.MethodThatThrows() Catch e As OutOfMemoryException Throw(new ApplicationException("Some application function failed!", e)) End Try End Sub End Class Questo codice dimostra un semplice tipo scritto
in Visual Basic e derivato da VCBase [Inherits
VCBase]... 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 } } ... la stessa cosa derivando in Intermediate Language la classe VBDerived definita qui sopra... 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"); } } ... ed infine l'analogo in C#, derivato dalla classe ILDerived [class CSDerived:ILDerived]. CrossLang.cs using System; using System.Security; class App{ public static void Main(){ try{ CrossObj(); }catch(VerificationException){ Console.WriteLine("A VerificationException has been thrown "+ "(and caught). Run this\nsample from your local "+ "hard-drive to avoid this exception."); } } 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(); } // Test sull'eccezione try{ (objects[2] as VBDerived).AnotherMethodThatThrows(); }catch(ApplicationException){ // Risponde al fallimento } } } CrossLang.cs darà forma all'assembly eseguibile. Per prima cosa viene creato un array nel quale saranno caricati gli oggetti creati sulla base di quelli definiti nei vari sorgenti presentati. In posizione 0 viene caricato l'oggetto creato a partire da ILDerived. Essendo l'oggetto derivato da VBDerived a sua volta discendente da VCBase i relativi "Constructor" saranno richiamati dando luogo all'output: Creating object: ILDerived Executing the VCBase::VCBase() constructor Executing the VBDerived.New() constructor Executing the ILDerived::ctor() constructor Analogamente, in posizione 1 dell'array è caricato l'oggetto creato da CSDerived, derivato da ILDerived derivato da VBDerived a sua volta ancora discendente da VCBase. L'output su console in questo caso risulta: Creating object: CSDerived Executing the VCBase::VCBase() constructor Executing the VBDerived.New() constructor Executing the ILDerived::ctor() constructor Executing the CSDerived.CSDerived() constructor Infine da VBDerived è creato l'oggetto posto nell'ultima locazione dell'array, ed essendo derivato direttamente da VCBase genera: Creating object: VBDerived Executing the VCBase::VCBase() constructor Executing the VBDerived.New() constructor A questo punto mediante foreach, che permette di scorrere un array (trattato separatamente in questo tutorial) il metodo virtuale presente in ogni oggetto viene eseguito: Calling Methods Executing the ILDerived::Method() virtual method Executing the CSDerived.Method() virtual method Executing the VBDerived.Method() virtual method Fonti: Documentazione .NET Framework SDK |