Le novità di C# 4.0

di: Matteo Baglini     03 Marzo 2010

Varianza

La possibilità di utilizzare tipi generici è stata introdotta sin dalla versione 2.0 di C# e del .NET Framework. Tuttavia esistono degli scenari, legati all'ereditarietà, non percorribili con l'attuale versione del linguaggio. Per capire meglio osserviamo il seguente frammento di codice.

IList<string> list1 = new List<string>();
IList<object> list2 = list1;

Dato che il tipo string è implicitamente convertibile a object, il precedente codice sembra perfettamente valido, però se proviamo a compilarlo otteniamo un errore di conversione, che in sostanza ci informa dell'impossibilità di convertire in maniera implicita IList<string> in IList<object>. Come mai? Questo limite è dovuto al fatto che l'interfaccia generica IList<T> rappresenta una collezione di elementi completamente modificabile, quindi, se ipoteticamente la conversione in fase di compilazione fosse possibile, potremmo scrivere codice come il seguente, con un risultato a run-time sicuramente disastroso.

list2[0] = 10;
string s = list1[0];

È anche vero che all'interno del .NET Framework esistono delle interfacce che hanno la caratteristica di fornire un accesso in sola lettura, quindi immuni al problema evidenziato poc'anzi.

Nel nostro esempio abbiamo utilizzato una collezione, quindi in questo caso il primo pensiero va subito all'interfaccia generica IEnumerable<T>, la quale definisce il contratto per iterare una collezione. Solo iterare. Nessuna possibilità di aggiungere o rimuovere elementi. Quindi una conversione da IEnumerable a IEnumerable può avvenire senza alcun effetto collaterale.

Da qui l'introduzione nel .NET Framework e in C# 4.0 del concetto di Varianza e nello specifico di covarianza e controvarianza, applicabile solo su delegati e interfacce generiche.

out

Tramite l'uso della parola chiave outparola chiave out, applicata ad parametro generico T, andiamo ad indicare al compilatore che quel tipo è covariante in T, quindi saranno ammesse conversioni da B ad A, qualora B erediti>da A. Supponiamo di avere una classe Rectangle che eredita da Shape, possiamo applicare la Covarianza ad un delegato come mostrato dal seguente codice:

delegate TResult Create<out TResult>();

Create<Rectangle> createRectangle = () => new Rectangle();
Create<Shape> createShape = createRectangle;

Console.WriteLine(createShape());

in

Diversamente la Controvarianza la otteniamo tramite la parola chiave in:

delegate void Print<in TArg>(TArg arg);

Print<Shape> printShape = arg => Console.WriteLine(arg);
Print<Rectangle> printRectangle = printShape;

printRectangle(new Rectangle());

Invariante

Possiamo anche applicare entrambe o nessuna restrizione alla definizione di un tipo generico. Come mostrato dalla seguente interfaccia, nella quale abbiamo definito TResult come covariante, TArg come controvariante e TProperty come invariante.

interface IMyInterface<out TResult, in TArg, TProperty>
{
  TResult Process(TArg arg);
  TProperty Property { get; set; }
}

Guide ASP.Net

Guida Windows Azure Code Snippets

Le migliori pratiche per far girare le applicazioni "in the cloud",...

Guida ASP.NET MVC Best Practices

Un workflow dettagliato e ricco di suggerimenti pratici per...

Guida ASP.NET Starter Kit

Un modo semplice per imparare ad utilizzare le tecnologie Microsoft...

Altre guide

Newsletter @Microsoft Dev

Ogni giovedì, direttamente nella tua e-mail: articoli, guide, tutorial e script ASP, ASP.Net, SQL server e IIS.

Iscriviti alla newsletter

Altre newsletter

Corsi in aula

Corso Progettazione database

11 Maggio 2012 a Milano
Disponibilità: 6 Posti

Amministratore di Reti Windows Server 2008

11 Giugno 2012 a Milano
Disponibilità: 5 Posti

Nessun corso previsto