C# Language Evolution

54
C# LANGUAGE EVOLUTION

description

Elementi di C# 1.0 Delegati ed eventi. Eccezioni. Enumeratori. Elementi di C# 2.0 Static Classes. Generics e collezioni generiche.Nullable Types. Partial Types e Partial Classes. Anonymous Methods.Iteratori, Elementi di C# 3.0 Auto-implemented properties.Object Initializers e Collection Initializers. Implicit Typed Variables. Anonymous Types.Extension Methods. Lambda Expression.

Transcript of C# Language Evolution

Page 1: C# Language Evolution

C# LANGUAGE

EVOLUTION

Page 2: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Agenda

C# Language Enhancements Evolution

What is new in C# 1.x

What is new in C# 2.0

What is new in C# 3.0

Page 3: C# Language Evolution

C# LANGUAGE

EVOLUTION

What is new in C# 1.x

Page 4: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Novità in C# 1.0

Reference Types

Value Types

Tipi primitivi

Struct

Class e Ereditarietà

Proprietà

Namespace

Enum

Delegates

Eventi

Eccezioni

Enumeratori

Attributi

Page 5: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Reference Types

Una qualsiasi dichiarazione di tipo fatta con la parola class indica un

Reference Type

Il riferimento è a una istanza di quel tipo

L’istanza viene creata con l’operatore new

Allocazione nel managed heap

L’assegnazione tra variabili di tipo Reference implica la copia del

riferimento, non dell’oggetto riferito

Una variabile di un reference type accetta null

Invalida il riferimento

Valore di default per una variabile

Non distrugge l’oggetto (Garbage Collection)

Far riferimento ad una variabile null solleva una NullReferenceException

Gli array e le stringhe sono reference types

Page 6: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Value Types

Nel caso di local variables, parameters, loop counters, un

programma ne può fare un uso intensivo

Problemi

Allocazione

Accesso

Rilascio

Uso dello stack

Allocazione e rilascio automatico

Accesso alla memoria efficiente

I value types contengono i valori direttamente, non i riferimenti

Int, char, byte, TimeSpan sono value types primitivi

Se ne possono definire di custom tramite struct

Page 7: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Tipi primitivi

I tipi primitivi sono strutture definite nel namespace

System

È possibile usare il loro nome o il loro

alias C#

Int32 i = 4;

int j;

j = i;

structure name

C# alias

bool Boolean

char Char

sbyte SByte

byte Byte

short Int16

ushort UInt16

int Int32

uint UInt32

long Int64

ulong UInt64

float Single

double Double

decimal Decimal

Boolean

character

integer

floating point

same type so

can interoperate

Page 8: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

struct

Possono avere proprietà, metodi, costruttori, membri,

implementare interfacce

Non possono:

Ereditarietà per classe

Valori inizializzati alla definizione

Non possono avere un custom default constructor (senza

parametri)

Un costruttore deve esplicitamente inizializzare tutte le

variabili

Page 9: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

class e ereditarietà

Class per definire reference type

Ereditarietà

Single rooted

Multiple Interface

“base” per referenziare la classe base

Le classi non sono polimorfiche di default

I membri non sono virtuali di default

Necessaria la parola chiave virtual

Per identificare un tipo si usa l’operatore is

<variable> is <type>

Page 10: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Proprietà

Le proprietà combinano la sintassi delle variabili

membro con il controllo delle funzioni membro

Permettono di associare ad un nome (con un tipo) le due

funzioni accessorie

Syntactic Sugar

Permettono di definire

Readonly properties

Guarded properties

Calculated properties

Page 11: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Namespace

Qualificano un insieme di classi sotto un unico nome contenitore

Nome COMPLETO della classe: nome del namespace + nome della classe

Livelli>1

Si definiscono in namespace {}

Permettono di disambiguare classi con lo stesso nome

È possibile usare sempre i nomi qualificati

È possibile importare un namespace con la parola chiave using

Permette di definire alias sul namespace: using <alias> = <namespace>

<alias>.<nome classe>

Permette di definire alias sulla classe: using <aliasclasse> = <namespace>.<classe>

<aliasclasse>

È possibile usare la parola using sia dentro che fuori del namespace

La differenza diventa “importante” nel caso nello stesso file ci siano più definizioni di

namespace

Spesso non succede

Esiste un “global” namespace

Page 12: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Enum

La parola chiave enum è usata per definire il nuovo

tipo

Contiene un insieme di costanti simboliche

È possibile definire variabili di un tipo enum, usando I

valori definiti in essa

Di default usa (implicitamente) il tipo int

È possibile fare il cast (esplicito) da/verso il tipo implicito

È possibile specificare un altro tipo primitivo (a parte char)

È possibile assegnare dei valori diretti

È possibile modificare la sequenza dei numeri

Page 13: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Delegate

La parola riservata delegate serve a definire un tipo in grado di puntare a un metodo e gestire indirettamente la sua invocazione.

Possiamo vedere un delegate come un "puntatore a funzione“

Garantisce che il metodo abbia una specifica firma

Lista ordinata dei tipi dei parametri formali

Non include il tipo di ritorno (ma due funzioni non possono distinguersi per il solo tipo di ritorno)

Offrono la possibilità di chiamare un metodo (anche) in modo asincrono tramite BeginInvoke e EndInvoke

Un delegato ha dei metodi (è una classe)

<delegate>() è la sintassi contratta di <delegate>.Invoke()

I delegati sono multicast

È possibile assegnare ad un delegate più puntamenti a metodi diversi

Un invocazione sul delegato implica la chiamata a tutti i metodi referenziati

Vengono utilizzati principalmente per:

la gestione degli eventi

L’uso come callback (passare un metodo come “valore” ad un altro metodo)

Page 14: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Eventi

Un evento caratterizza un componente

Qualcosa che succede all’interno del componente e che lo stesso notifica

Un oggetto esterno può sottoscrivere l’evento per essere notificato quando succede

Un evento è una specializzazione di un delegato

event è una parola chiave da associare ad una proprietà di un tipo delegato

event impedisce l’uso dell’assegnazione (“=“) ma solo la sottoscrizione (“+=“) o la

cancellazione (“-=“)

Il mancato uso dell’assegnazione impedisce ad un consumatore generico di rimuovere la

sottoscrizione a qualche altro componente

Qualsiasi delegato può essere usato per un evento

È convenzione usare un delegato del tipodelegate void <event handler>(object sender, <event args> e)

dove <event args> è una classe che deriva da EventArgs

È possibile creare una variabile membro di tipo evento

È possibile creare una proprietà di tipo evento

Rispetto alle proprietà le funzioni accessorie sono add e remove

Page 15: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Eccezioni

Un’eccezione è un evento sincrono

È prevedibile il punto in cui può avvenire, non il momento

Un’eccezione è un pattern utilizzato per notificare errori

Un’eccezione può essere gestita con un blocco try…catch…finally

Try: blocco che può generare eccezione

Catch: blocco eseguito subito dopo all’istruzione nel blocco try che ha generato l’eccezione

Finally: blocco eseguito comunque dopo il blocco try e l’eventuale blocco catch

Un’eccezione, per essere gestita dal blocco try prende forma di un oggetto che deriva dalla classe

exception

La notifica di un’eccezione si basa sullo stack

Un blocco try…catch…finally viene registrato nello stack

Non è detto che un metodo che chiama un altro metodo che genera una eccezione debba “trappare” una

eccezione

Viene fatto uno “stack walk” per trovare il primo blocco disponibile

Eventualmente quello di default fornito dal framework

È possibile definire una eccezione derivando una nuova classe dal tipo Exception

Si usa l’istruzione throw per sollevare una nuova eccezione

Ci sono delle eccezioni di uso comune

Page 16: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Eccezioni comuni

System.ArgumentException

Thrown when a function is called with a bogus argument. This generally indicates a program bug.

System.ArgumentNullException

Thrown when a function argument is (unexpectedly) null. (It is a subclass of ArgumentException.

System.ArgumentOutOfRangeException

Thrown when a (usually numeric) argument is too big or too small. (It is also a subclass of ArgumentException.) For example, this is

thrown when passing a negative number into a function that accepts only positive values.

System.InvalidOperationException

Thrown when the state of an object is unsuitable for a method to successfully execute, regardless of any particular argument values.

Examples include reading an unopened file or getting the next element from an enumerator where the underlying list has been

modified partway through the iteration.

System.NotSupportedException

Thrown to indicate that a particular functionality is not supported. A good example is calling the Add method on a collection for

which IsReadOnly returns true.

System.NotImplementedException

Thrown to indicate that a function has not yet been implemented.

System.ObjectDisposedException

Thrown when the object upon which the function is called has been disposed.

Page 17: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Enumeratori

Un enumeratore è un cursore read-only forward only

Permette di visitare una collezione di elementi

Si basa su due interfacce

IEnumerator: l’enumeratore vero e proprio

IEnumerable: permette di richiedere ad una collezione un

enumeratore per visitare la stessa

Usato dal costrutto foreach

Page 18: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Attributi

Permettono di associare metadati agli elementi di definizione di una classe

(classe, metodo, variabile, proprietà, …)

Sono informazioni disponibili a runtime tramite reflection

<object>.GetType().GetMember()

Permettodo di implementare algoritmi basati sulla struttura stessa della

classe, decidendo in base agli attributi

Un esempio su tutti: serializzazione

Atttributi Standard (dalla BCL)

Attributi Custom

Classi derivate da System.Attribute

Accessibili tramite Attribute.GetCustomAttribute(<memberinfo>)

Sintassi:

[<attribute>Attribute(positional parameters, named parameters….)]

Page 19: C# Language Evolution

C# LANGUAGE

EVOLUTION

What is new in C# 2.0

Page 20: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Novità in C# 2.0

Static Classes

Generics

Nullable Types

Partial Types

Anonymous Methods

Iterators

Page 21: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Static Classes

Contengono solo metodi statici

Non membri di istanza

Serviranno per gli Extension Methods

public static class Math

{

public static double Sin(double x) {…}

public static double Cos(double x) {…}

}

Page 22: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Generics

Cosa sono i generics?

Polimorfismo Parametrico

Funziona sia con reference and value types

Controllo dei tipi in fase di dichiarazione

No boxing (value types)

No downcasts (no object)

Supporto completo a runtime

Reduced code bloat

Non bisogna scrivere classi wrapper tipizzate

Page 23: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Come possono essere usati?

Con varie definizione di tipo

Class, struct, interface and delegate

Per specificare variabili membro, parametri, valori di

ritorno

Page 24: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Generic Collections and Interfaces

System.Collections.Generic classes List<ItemType>

Dictionary<K,V>

Stack<ItemType>

Queue<ItemType>

System.Collections.Generic interfaces IList<ItemType>

IDictionary<K,V>

ICollection<ItemType>

IEnumerable<ItemType>

IEnumerator<ItemType>

IComparable<OperandType>

IComparer<OperandType>

Page 25: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Various other Generic Classes

System.Collections.ObjectModel classes

Collection<T>

KeyedCollection<T>

ReadOnlyCollection<T>

Various Other Classes

Nullable<T>

EventHandler<T>

Comparer<T>

Page 26: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Nullable types

Int è un value type e non può accettare il null (reference type)

Utile nel momento in cui mappiamo gli attributi di una tabella di database (tutti

gli attributi di una tabella di DB possono essere nullabili)

Applicazione dei generics

Nullable<T>

T è un tipo primitivo (value type/struct)

Rende possibile la sintassi

int? x = null;

Int? è equivalente a Nullable<int>

Il cast può essere:

Implicito: int? x = 5;

Esplicito: int y = (int) x; // perché bisogna verificare se non sia null

int y = 0;

if (x.HasValue) y = (int) x;

Page 27: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Tipi parziali (Partial Types)

È possibile spezzare una dichiarazione in più files

Utile quando c’è un designer/generatore di codice

Ottimo anche per organizzare il codice

Una partial class per ogni interfaccia implementata

Tipi supportati

Classes (Partial Classes)

Struct

Interface

Divisi a design time, “fusi insieme” a compile time

Page 28: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Anonymous Methods

Permettono di definire direttamente il codice dove è

necessario un delegato

Il tipo dei delegati viene automaticamente

inferenziato (non serve istanziare esplicitamente il

delegato, ma scrivere solo il corpo)

button.Click += delegate(object sender, EventArgs e) {MessageBox.Show(((Button)sender).Text);

};

Page 29: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Anonymous Methods

I blocchi di codice possono accedere alle variabili locali

Non possono però accedere a parametri (di un metodo in

cui sono definiti) ref o out

Ovvio, in quanto la loro esecuzione non è legata

all’invocazione del metodo di definizione

La vita delle variabili locali è “estesa” fino a che il delegato

che le referenzia non è eligibile di garbage collection

Tutto è dovuto a generazione nascosta di classi

int n = 0;

Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n);

};

Page 30: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Iteratori

È possibile usare la

parola chiave yield

yield return e yield

break

Bisogna restituire

IEnumerator o

IEnumerable

public class List{

public IEnumerator GetEnumerator() {for (int i = 0; i < count; i++) {

yield return elements[i];}

}}

Page 31: C# Language Evolution

C# LANGUAGE

EVOLUTION

What is new in C# 3.0

Page 32: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

What is new in C# 3.0

Auto-Implemented Properties

Object Initializers

Implicit Typed Variables

Anonymous Types

Extension Methods

Partial Methods

Lambdas

Expression Trees

The “real”Query Expressions

Page 33: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Autoimplemented Properties

Permettono di specificare una proprietà senza doverne specificare il field

privato

Velocizza il processo di creazione di proprietà all’interno delle classi

Il membro privato viene generato a compile-time

Per vedere il nome del field privato generato, è necessario utilizzare

ildasm.exe o Reflector.exe

Non è possibile utilizzarle per specificare proprietà in read-only o write-

only

E’ possibile limitare l’accesso al get o al set di una proprietà, specificandone la

visibilità

Non è possibile specificare un valore di default a causa del membro

privato che non è presente

Nel costruttore della classe si può intervenire impostando il valore di default

Page 34: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Object Initializers

È possibile inizializzare variabili membro e proprietà,

senza richiamare il costruttore in modo esplicito

new C(1, 2, name=“my class”);

Valgono le regole di visibilità

È possibile fare annidamento

Initializzare grafi

Collection initializers

List<int> digits = new List<int> { 0, 1};

Deve implementare System.Generic.ICollection<T>

Object initializers

var a = new Point { X = 0, Y = 1 };

Page 35: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Implicitly typed variables

E’ possibile dichiarare le variabili in modo implicito, utilizzando la parola chiave

“var”

var i = 5;

var s = "Hello";

var d = 1.0;

var orders = new Dictionary<int,Order>();

Il tipo delle variabili è indotto dalla espressione che lo inizializza

DEVE INCLUDERE L’INIZIALIZZAZIONE

“var” non è variant o object

È comunque statically typed

Non può essere null

Var può essere usata SOLO nei metodi

Non può essere usata a livello di classe

Attenzione all’abuso

Bisogna capire il contesto dell’esecuzione per capire cosa c’è dentro

E’ possibile utilizzare la keywork “var” anche all’interno di cicli for e foreach

Page 36: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Anonymous Types

È una “tupla” le cui proprietà specifiche sono inferenziate tramite Object Initializer

Viene fatto a compile time, quindi è sempre comunque statically/strongly typed

Internamente viene creata una classe nascosta

var x = new {p1 = 10, p2 = “name”};

Il tipo di x è anonimo

Non è possibile referenziarlo “per nome” da codice

structural type equivalence

Due tipi anonimi possono essere compatibili

Viene ricostruita la “compatibilità” a compile time

Viene definito un solo nuovo tipo (anonimo)

La classe verrà generata automaticamente in fase di compilazione, e deriverà da System.Object

implicitly typed arrays

var a = new[] { 1, 10, 100, 1000 };

Devono avere tipi compatibili

O conversioni implicite

Page 37: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Extension methods

È possibile aggiungere metodi a classi già definite

È possibile aggiungere metodi a classi già compilate, in assembly diversi

Non sono mixin (dai dynamic languages)

Sono “syntactic sugar”

Readability

Solo metodi

Non per properties, events, operators (almeno per adesso)

Metodi statici in classi statiche

La chiamata esplicita al metodo statico avviene sempre (e rimuoveambiguità)

Nel caso di sovrapposizione con metodi locali

I metodi locali hanno la precedenza

L’inserimento degli extension method avviene al momentodell’importazione del namespace

Page 38: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Extension methods

public static class Extensions

{

public static int ToInt32(this string s) {

return Int32.Parse(s);}

public static T[] Slice<T>(this T[] source, int index, int count) {

if (index < 0 || count < 0 || source.Length – index < count)

throw new ArgumentException();T[] result = new T[count];Array.Copy(source, index, result, 0, count);return result;

}

}

Page 39: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Partial Methods

E’ stata aggiunta la possibilità di definire un metodo come “partial”

Permette di definire un metodo in una parte della classe, e poterlo implementare in un’altra parte della classe

Utile in caso di uso dei generatori di codice

Non necessità di ereditarietà di metodi virtuali

I metodi dichiarati come “partial” hanno delle limitazioni:

Devono essere definiti all’interno di una partial class

Devono sempre ritornare void

Possono avere argomenti, ma non con clausula “out”

Sono sempre implicitamente privati

Se un metodo partial non viene implementato, questo non compare nel codice compilato (nemmeno la chiamata del metodo)

Page 40: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda expressions

Permettono di definire delle funzioni “inline”, associando direttamente un blocco di codice

Permettono di creare un metodo “stand-alone” all’interno del codice (utilizzando gli anonymous methods)

Sono un’ulteriore semplificazione rispetto l’uso dei delegate

Dal calcolo lambda x . x + 1

In C# 3.0 x => x + 1

Dalla sintassi delle anonymous functions delegate(int x) { return x + 1;}

Possono usare variabili implicitamente tipizzate

Possono avere più di una variabile

Il corpo può contenere espressioni o istruzioni

Page 41: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Esempi di Lambda Expressions

x => x + 1

// Implicitly typed, expression body

x => { return x + 1; }

// Implicitly typed, statement body

(int x) => x + 1

// Explicitly typed, expression body

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

// Explicitly typed, statement body

(x, y) => x * y

// Multiple parameters

() => Console.WriteLine()

// No parameters

Page 42: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda to Delegates

Una lambda expression è un valore,che non ha tipo, ma può essere convertito in un particolare delegato

delegate R Func<A,R>(A arg);

Func<int,int> f1 = x => x + 1;// Ok

Func<int,double> f2 = x => x + 1;// Ok

Func<double,int> f3 = x => x + 1;// Error – double cannot be// implicitly converted to int

Nel framework sono predefiniti dei delegates “standard”

public delegate TResult Func<TResult>();

public delegate TResult Func<T, TResult>(T a);

public delegate TResult Func<T1, T2, TResult>(T1 a, T2 b);

public delegate TResult Func<T1, T2, T3, TResult>(T1 a, T2 b, T3 c);

public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 a, T2 b, T3 c, T4 d);

public delegate void Action();

public delegate void Action<T>(T a);

public delegate void Action<T1, T2>(T1 a, T2 b);

public delegate void Action<T1, T2, T3>(T1 a, T2 b, T3 c);

public delegate void Action<T1, T2, T3, T4>(T1 a, T2 b, T3 c, T4 d);

Page 43: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Expression trees

Forniscono una rappresentazione ad oggetti di una lambda expression.

Sono assimilabili agli AST generatida un compilatore per creare ilcodice “a compiler time”

L’expression tree è accessibile a runtime

Le lambda expression possonoessere convertite in un expression tree

Expression<Func<T>> e = x => x + 1;

Sono compilati, strong-typed, provider independent e serializzabili.

Sono Immutabili, e quindi per modificarne una sua parte, si deve creare un nuovo Expression Tree

Page 44: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Visita e costruzione

di un Expression Tree// Create an expression tree.

Expression<Func<int, bool>> exprTree = num => num < 5;

// Decompose the expression tree.

ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];

BinaryExpression operation = (BinaryExpression)exprTree.Body;

ParameterExpression left = (ParameterExpression)operation.Left;

ConstantExpression right = (ConstantExpression)operation.Right;

Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",

param.Name, left.Name, operation.NodeType, right.Value);

/* This code produces the following output:

Decomposed expression: num => num LessThan 5

*/

// Create the parameter "x" in x + 1

ParameterExpression p0 = Expression.Parameter(typeof(int), "x");

// Create the constant 1 in x + 1

ConstantExpression c0 = Expression.Constant(1);

// Build the addition expression x + 1 using the above

// Note it will really look like Add(x,1)

BinaryExpression expression = Expression.Add(p0, c0);

// Create the Lamda Expression x => Add(x,1)

var lambdaExpression = Expression.Lambda<Func<int,int>> (expression, new ParameterExpression[] { p0 });

// Let's compile it so we can use it

var theDelegate = lambdaExpression.Compile();

// Execute... 6 + 1 = 7

var seven = theDelegate.Invoke(6);

Page 45: C# Language Evolution

C# LANGUAGE

EVOLUTION

The “real” LINQ: Query Expression

Page 46: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Query Expressions

Fornisce delle API che permetteno di eseguire delle query

expression (sia in lettura che scrittura) verso classi che

implementano IEnumerable<T>, database relazionali,

DataSets, o documenti XML. (etc etc ...)

Definiscono delle query verso una sorgente dati,

utilizzando dei query operators (es: from, in, where,

orderby, e select)

Le LINQ query expression sono strongly typed. Il

compilatore verificherà la corretta sintassi delle query.

Il tipo di dati ritornato è del tipo IEnumerable<T>

Page 47: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Query Expressions

Query expressions or LINQ (Language INtergrated Queries) are the key feature of .NET 3.5

Query expressions are translated to method calls works on classes like: delegate R Func<A,R>(A arg);

class C<T>

{

public C<T> Where(Func<T,bool> predicate);

public C<S> Select<S>(Func<T,S> selector);

public C<S> SelectMany<S>(Func<T,C<S>> selector);

public O<T> OrderBy<K>(Func<T,K> keyExpr);

public O<T> OrderByDescending<K>(Func<T,K> keyExpr);

public C<G<K,T>> GroupBy<K>(Func<T,K> keyExpr);

public C<G<K,E>> GroupBy<K,E>(Func<T,K> keyExpr, Func<T,E> elemExpr);

}

Page 48: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Sintactic sugar

string[] londoners =

from c in customers

where c.City == “London”

select c.Name;

string[] londoners =

customers.

Where(expression).

Select(expression);

Page 49: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda Expressions

What is this?

customers.Where(City == “London”)Expression?

Code fragment?

vertices.Where(X > Y)

Anonymous method?

vertices.Where(delegate(Point p) { return p.X > p.Y; })

Local Query

Data Structure?

Page 50: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda Expressions

Remote Query

customers.Where()

==

c.City “London”

customers.Where(Expr.Delegate(Expr.Param(“c”),Expr.EQ(

Expr.Property(Expr.Param(“c”),

“City”),Expr.Literal(“London”))

Remotable

Inspectable

delegate(Customer c) {return c.City == “London”}

IL doesn’t travel wellGood for API’s

But please don’t make me write this

Still no type checking?

AST

Page 51: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda Expressions

customers.Where(City == “London”)

delegate(Customer c) {return c.City == “London”}

Expr.Delegate(Expr.Param(“c”),Expr.EQ(Expr.Property(

Expr.Param(“c”),“City”),

Expr.Literal(“London”)))

Better if something like this …

could become this

or this

Page 52: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Lambda Expressions

public delegate Func<T,bool>(T t)

Func<Customer,bool> f = c => c.City == “London”;

Parameterized fragments of code

Coercible to delegates

Expression<Func<Customer,bool>> e = c=> c.City == “London”;

or Expression typesSyntax is the same

Page 53: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Definizione ed esecuzione

La definizione di una query è differente dalla sua

esecuzione

Questo è necessario perché il modello di

interrogazione deve essere componibile

Componibile è necessario per rendere “accettabile” la

definizione della query

Vale soprattutto se l’esecuzione deve essere eseguita

remotamente (da una definizione locale)

Si parla di esecuzione “differita” (DEFERRED)

Page 54: C# Language Evolution

Introduzione al .NET Framework – Marco Parenzan

Query Execution

Una query expression

viene eseguita quando

viene valutataint[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 };

var subset = from i in numbers where i < 10 select i;

// LINQ statement evaluated here!

foreach (var i in subset)

Console.WriteLine("{0} < 10", i);

// Change some data in the array.

numbers[0] = 4;

// Evaluate again.

foreach (var j in subset)

Console.WriteLine("{0} < 10", j);

• Per avere una esecuzioneimmediata della query, si possonoutilizzare i metodi ToArray<T>(), ToDictionary<TSource,TKeyint[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 };

// Get data RIGHT NOW as int[].

int[] subsetAsIntArray =(from i in numberswhere i < 10 select i).ToArray<int>();

// Get data RIGHT NOW as List<int>.

List<int> subsetAsListOfInts = (from i in numbers where i < 10 select i).ToList<int>();