Giovedì ho trovato il tempo di installare sulla mia macchina la nuova versione di Visual Studio 2010 beta 1. Leggendo i vari documenti sulle novità, la mia curiosità è stata attratta dalle novità del linguaggio C# della version 4.0. Da quel che ho capito sono quattro le novità:
- Dynamic Typed Objects
- Optional and Named Parameters
- Improved COM Interoperability
- Co/Contra-Variance
Sui dynamic ho avuto proprio una discussione sul fatto che la keywork dynamic non centra nulla con var. La dichiarazione di un oggetto come dynamic, crea effettivamente un oggetto di tipo dinamico in runtime ed elaborato in late-binding, con tutti i problemi che ne derivano!
Scrivere queste linee di codice ora è perfettamente corretto:
dynamic az = "Andrea"; Console.WriteLine(az); // Andrea az = 14; az = 14 * 2; Console.WriteLine(az); // 28 az = new System.Data.DataTable(); Console.WriteLine(az.GetType()); // System.Data.DataTable
Ma questo nuovo oggetto è utilizzabile anche nelle dichiarazioni di metodi e altro:
Dynamic1("aa"); Dynamic1(12); ... static void Dynamic1(dynamic value) { if (value is string) Console.WriteLine(value + " is a string!"); if (value is int) Console.WriteLine(value + " is a int!"); }
Ma la potenzialità del dynamic vanno ben oltre. E' possibile ora chiamare oggetti COM in modo molto più semplice, ed è diventato anche banale caricare runtime una dll e utilizzarne i metodi. Per esempio, avevo questa classe in una dll esterna:
namespace TestDynamic { public class Utilities { public string GetAll(string name) { return string.Format("{0}: {1}", name, DateTime.Now); } } }
Possiamo caricarla e utilizzarla con i dynamic (senza reference). Un esempio di codice che fa questo:
dynamic mya = Assembly.LoadFile("../class.dll"); Type myaClassType = mya.GetType("TestDynamic.Utilities"); dynamic myaDemoClassObj = Activator.CreateInstance(myaClassType); string val = myaDemoClassObj.GetAll("az");
Facile e comodo? Può essere, ma l'utilizzo del dynamic non è immune da problemi. Innanzitutto prestazionale: come detto prima, tutto ciò che è dynamic è elaborato in runtime/late-binding, dunque con tutti i problemi di prestazioni che ne derivano. L'esempio di codice qui sopra, se confrontato con un metodo tradizionale di loading di una dll e utilizzo del reflector o, meglio, di interfacce, perde su tutti i fronti. Secondo problema: Visual Studio 2010 non è in grado di fornici l'intellisense:
L'utilizzo dei parametri opzionali o dichiarandone il nome è una di quelle novità che ricordano tanto ciò che Visual Basic offre da parecchio tempo:
public string MyMethod(int Id = 0, string Name = "AZ") { ... }
Che crea in automatico gli overload del metodo passando ai parametri i valori di default specificati:
MyMethod(); MyMethod(1); MyMethod(1, "Andrea");
E se nell'esempio sopra volessimo passare solo il parametro Name e non l'Id? Questo codice ci darebbe errore, perché si aspetta in ogni caso come primo parametro un int:
MyMehotd("Andrea");
Una delle altre novità di C# 4.0, è la possibilità di dichiarare oltre al valore anche il parametro a cui sarà assegnato:
MyMethod(Name: "Andrea"); MyMethod(Name: "Andrea", Id: 1);
L'ultima novità, Covariance e Contravariance. La covariance permette di trattare gli oggetti come il tipo da cui deriva. Per esempio, avendo le classi:
public class First { } public class Second : First { }
Possiamo scrivere:
First[] coll = new Second[20];
Ma non possiamo in alcun modo utilizzare questa possibilità nel caso dei generic essendo il C# a cui siamo abituati invariant:
List<Second> xsecond = new List<Second>(); List<First> xfirst = xsecond; Cannot implicitly convert type 'System.Collections.Generic.List<Test1.Second>' to 'System.Collections.Generic.IList<Test1.First>'.
Attualmente ci sono altri metodi per copiare un oggetto o una collection di oggetti (cast o Linq). Con la nuove versione di C#, abbiamo una nuova tecnica ma, come scritto sopra, per ora è possibile solo con le interfacce e delegate modificare questo comportamento:
public class Other<T> where T : First // Or without constraint { } public class Other2<T> : IOther2<T> { } interface IOther2<out T> { }
Ora, grazie all'interfaccia (e la specifica del generic T con out), possiamo utilizzare anche gli oggetti derivati della nostra classe:
var xot2 = new Other2<Second>(); IOther2<First> xot21 = xot2;
La keyword out è utilizzata per specificare gli oggetti in output, mentre in come è facilmente intuibile è utilizzabile come parametro input di metodi con i delegate, eccole utilizzare entrambe con i delegate:
delegate T Func1<out T>(); delegate void Action1<in T>(T a); ... // Covariance Func1<Second> secondx = () => new Second(); Func1<First> firstx = secondx; // Contravariance Action1<First> act1 = (ani) => { Console.WriteLine(ani.ToString()); }; Action1<Second> cat1 = act1; cat1(new Second());
Ho detto qualcosa di inesatto? E' facile che sia così: il mio studio sulle novità di questo linguaggio si basano su test e letture che il poco tempo libero attuale mi permette. Questa scusa mi lascia scevro di responsabilità? Se ne sono convinto io...
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- Plinq in tram, il 25 maggio 2014 alle 22:18
- Asincronia, l'8 febbraio 2014 alle 22:30
- Disabilitare tutti i web control in una pagina?, l'8 luglio 2009 alle 14:21