Introduzione a C# 3.0

3 pagine in totale: <<Indietro 1 2 [3]

L'esempio seguente mostra tre semplici casi di utilizzo. Il metodo IsNull estende il tipo System.Object ed esegue la verifica se un determinato oggetto è nullo, il metodo IsOdd estende il tipo System.Int32 verificando che un numero intero sia dispari, infine il metodo ToInt32 estende il tipo System.String operando la conversione di una stringa in un intero.

namespace AspItalia.Orcas
{
  public static class Extensions
  {
    public static bool IsNull(this object obj)
    {
      return obj == null;
    }

    public static bool IsOdd(this int i)
    {
      return i % 2 == 1;
    }

    public static int ToInt32(this string s)
    {
      return Int32.Parse(s);
    }
  }
}

using AspItalia.Orcas;

// ...
// ...
// ...

var s = "Riccardo";
var isNull = s.IsNull(); // Equivale a Extensions.IsNull(s)

var i = 3;
var isOdd = i.IsOdd(); // Equivale a Extensions.IsOdd(i)

var x = "180805";
var y = x.ToInt32(); // Equivale a Extensions.ToInt32(x)

Lambda expressions

Le lambda expressions sono per molti aspetti equivalenti agli anonymous methods a tal punto che si può affermare che un'adozione più tempestiva delle lambda expressions in C# avrebbe probabilmente reso inutili gli anonymous methods. L'esigenza da cui scaturiscono le lambda expressions consiste nella possibilità di trattare il codice come i dati nel passaggio dei parametri ad un metodo. Le lambda expressions, così come gli anonymous methods e i predicati, forniscono pertanto un meccanismo utile allo scopo, estendendo la gamma dei valori utilizzabili come parametro fino a includere i blocchi di codice. In sostanza, le lambda expressions forniscono un modo più compatto e funzionale per definire anonymous methods.

Una lambda expression si compone di tre parti:

  • un elenco di parametri compresi in una coppia di parentesi tonde (facoltative se il parametro è uno solo) per i quali può essere o meno indicato il tipo corrispondente;
  • l'operatore =>;
  • un'espressione, un'istruzione o un blocco di codice che usa i parametri e che fornisce un valore di ritorno.

Ecco alcuni esempi, che prendono in considerazione le varie opzioni di sintassi possibili.

x => x + 1 // Parametro tipizzato implicitamente
x => { return x + 1; }

(int x) => x + 1 // Parametro tipizzato esplicitamente
(int x) => { return x + 1; }

(x, y) => x + y // Usa un'espressione
(x, y) => { return x + y; } // Usa un blocco di codice

(int x, int y) => x + y
(int x, int y) => { return x + y; }

() => Console.WriteLine("Hello, World!") // Nessun parametro

Prendiamo in considerazione il primo caso mostrato nell'esempio appena visto, ovvero x => x + 1. Se definiamo un delegate generico che rappresenta una funzione che, dato un argomento di tipo A, ritorna una valore di tipo R, la riga 3 e la riga 4 nell'estratto di codice seguente sono del tutto equivalenti:

delegate R Func<A,R>(A argument);
Func<int, int> f;

f = x => x + 1;
f = delegate(int x) { return x + 1; }

Quando per i parametri dell'espressione non viene specificato il tipo corrispondente, esso viene ricavato in modo implicito tramite type inference. Un discorso analogo vale anche per il tipo del valore di ritorno. Occorre peraltro prestare attenzione alla compatibilità tra i tipi ed, in particolare, alle possibilità di operare conversioni implicite. Riprendendo il tipo delegate dell'esempio precedente, il codice seguente mostra un caso significativo di incompatibilità, dovuto al fatto che il tipo System.Int32 non può essere convertito implicitamente in System.Byte:

Func<byte, int> a = x => x + 1; // OK
Func<int, byte> b = x => x + 1; // Errore

Expression trees

Gli expression trees permettono alle lambda expressions di essere rappresentate non tanto come codice, ma come insiemi di dati. L'idea di fondo è quella di rendere possibile una cosa del genere:

var contactsWithEmail =
  contacts.Select(c => string.IsNullOrEmpty(c.EmailAddress) == false);

Cosa significa questo esempio? In questo caso il parametro della funzione è una espressione che viene passata al metodo Select affinchè possa selezionare e ritornare i risultati per i quali l'espressione risulta essere vera. Il vantaggio di un approccio di questo tipo è che il criterio di selezione può essere effettivamente controllato dal compilatore, non essendo rappresentato da un dato come, per esempio, una stringa, in cui sia possibile inserire valori non validi da un punto di vista semantico.

Conclusioni

Le novità di C# 3.0 sono molto interessanti. Tra queste merita una menzione particolare la type inference che, come si è visto, consente in varie circostanze di ricavare in modo dinamico il tipo delle variabili, rendendo il codice molto compatto e meno verboso rispetto all'approccio, per così dire, classico. Molte delle novità mostrate come lambda expressions ed expressions trees ruotano comunque intorno a LINQ, che rapprsenta in ogni caso la novità più importante del linguaggio e per il quale si rimanda all'articolo specifico.

Lo speciale completo

3 pagine in totale: <<Indietro 1 2 [3]

Contenuti dell'articolo

Commenti
Dai un voto a questo articolo, ci aiuterà a migliorare il nostro sito (1 è il voto minimo, 5 il massimo).

Per procedere al rating dell'articolo devi essere autenticato.

Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.



TUTORIALS


IN EVIDENZA
MISC