Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Archive for March, 2008

Linq: Panoramica delle Funzionalità

Posted by Ricibald on 7th March 2008

Prima di leggere questo post consiglio a chi non ne fosse a conoscenza di leggere le novità del Framework 3.5 di .NET.

La più grande novità per lo sviluppatore inclusa nel .NET Framework 3.5 è senza dubbio LINQ. LINQ è l’acronimo per Language INtegrated Query.

Cosa è LINQ

LINQ non è altro che un’estensione del linguaggio che permette di eseguire query verso una determinata risorsa. La sintassi di query rimane la stessa e la risorsa può essere:

  • un file XML (LINQ To Xml): più semplice e veloce rispetto a utilizzare XPath
  • una collection di classi (LINQ To Objects): più semplice che ciclare gli elementi uno a uno
  • un database (LINQ To SQL): più sicuro e performante che invocare sql realizzate a run-time

La maggior parte delle funzioni di LINQ si basano sulle nuove caratteristiche del Framework. Soprattutto:

Di fatto la parte più interessante è il LINQ To SQL e rappresenta l’implementazione Microsoft della tecnica ORM.
Supporta transazioni, viste e stored procedure. Fornisce inoltre un semplice modo per integrare validazione dei dati e logica di business direttamente nel modello dati.

Come funziona LINQ

Come funziona? Semplice: Eseguo “Add -> New Item -> Linq To SQL Classes” e creo Universita.dbml.
Nel designer si possono trascinare tabelle e stored procedure e verranno automaticamente create:

  • classe UniversitaDataContext, che contiene tutti gli oggetti (Universitas, …) e metodi (stored procedure) del db, tipizzati fortemente
  • classi varie che rappresentano la versione tipizzata delle singole tabelle (Universita, Studente, …)

Realizza in questo modo un efficace ORM. Le classi sono fortemente tipizzate e le proprieta’ inserite devono essere quindi conformi al
tipo dichiarato nello schema del db, altrimenti verranno sollevati errori di compilazione (impossibile convertire da string a int…).
Il collegamento tra i controlli web e LINQ si ottiene tramite il nuovo LinqDataSource.

Un Esempio Pratico

Immaginiamo di avere un semplice db con due tabelle: studente e università, in cui studente ha un vincolo di integrità referenziale
verso università. Dopo aver trascinato le due tabelle nel designer e aver salvato il file Universita.dbml possiamo utilizzare le classi
generate nel seguente modo:

UniversitaDataContext db = new UniversitaDataContext();
Studente s = new Studente() { Matricola = "1234" };
Universita u = new Universita() { Name = "Roma Tre" };
u.Studenti.Add(s);
db.Universitas.Add(u);
db.SubmitChanges();

Questo creerà la corrispondente istruzione SQL trasferendo in modo atomico le modifiche apportate all’oggetto dall’ultimo submit:
mantiene quindi un sistema di versioning in modo automatico e un contesto di transazione.
Le classi generate sono parziali, e questo consente di apportare modifiche e/o aggiunte alla classe generata dal designer.

Personalizzazione del comportamento

Le proprieta’ (colonne) possono essere caricate su richiesta (lazy loading) impostando a true la proprieta’ Delay Loaded.

Le classi definiscono dei punti di estensibilità tramite metodi partial, che rappresentano una novità del framework 3.5. In tali punti si possono definire le azioni da eseguire prima e/o dopo aver settato una proprietà. Risultano utili per inserire validazione dei dati non verificabili dal db, come il check del formato email. I metodi parziali che vengono definiti sono:

partial void OnXXXChanging(YYY value);
partial void OnXXXChanged();

dove XXX è il nome della proprietà, e YYY il suo tipo.

In questo modo possiamo validare il formato dei dati, ma non la logica di inserimento. Se ad esempio vogliamo che la proprietà DataIscrizione
sia minore di DataLaurea allora dobbiamo eseguire tale controllo in un punto separato. Per questo viene messo a disposizione un ulteriore
metodo parziale per gestire questo differente tipo di logica di validazione:

partial void OnValidate(ChangeAction action);

In modo analogo, per definire una logica customizzata prima di un INSERT, UPDATE e DELETE, nella classe UniversitaDataContext
saranno disponibili i punti di estensione:

partial void InsertStudente(Studente instance);
partial void UpdateStudente(Studente instance);
partial void DeleteStudente(Studente instance);
partial void InsertUniversita(Universita instance);
partial void UpdateUniversita(Universita instance);
partial void DeleteUniversita(Universita instance);

Normalmente saranno utilizzate nel seguente modo:

public partial class UniversitaDataContext {
    partial void InsertStudente(Studente instance) {
        // TODO: custom insert validation logic
        this.ExecuteDynamicInsert(instance);
    }
}

Stored Procedure

Le stored procedure possono essere aggiunte semplicemente trascinandole nel designer. Se non restituiscono un tipo specifico
(Studente o Universita) non ha senso utilizzare quello automaticamente generato (che potrebbe cambiare in caso di conflitti).
Utilizzare var in questo caso. Un esempio pratico: trascino la stored procedure GetMatricoleStudenti nel designer e scrivo:

UniversitaDataContext db = new UniversitaDataContext();
foreach(Universita univ in db.Universitas) {
    var matricoleStudenti = db.GetMatricoleStudenti(univ.Id);
    foreach(var matricolaStudente in matricoleStudenti) {
        Console.WriteLine(matricolaStudente.Matricola);
    }
}

Se le stored procedure restituiscono un insieme di dati compatibile con una determinata tabella (ad es.Studente), allora si può trascinare la stored procedure
direttamente NELLA tabella e tale stored procedure restituirà quindi un risultato IEnumerable<Studente>.

Si possono anche gestire risultati con forme multiple (una stored procedure potrebbe restituire diversi record set a seconda
del flusso dell’operazione). In questo caso non possiamo trascinare la stored procedure nel modo usuale, ma richiamarla “a mano” via codice
(sempre nella classe UniversitaDataContext) dichiarando le possibili classi restituite tramite l’attributo ResultTypeAttribute.

Si possono anche definire in ogni tabella operazioni personalizzate di INSERT, DELETE, UPDATE in modo da collegarle
a una particolare stored procedure.

Conclusioni

Ricordate quando avevo detto che LINQ To SQL rappresenta l’implementazione Microsoft ORM? Non è completamente vero… Di fatto rappresenta un modo tipizzato per accedere alle proprietà del db. Osserviamo ad esempio l’analisi di Pietro Brambati. La relazione molti-a-molti autore-libro viene fatta corrispondere alle tre tabelle che il db rappresenta. Un’altra critica che è stata mossa è il fatto che le classi generate (Studente, Università, …) sono di fatto “sporcate” con tanti attributi e metodi che non si vorrebbero vedere nei
propri oggetti di dominio.

Per questo esiste il progetto LINQ to Entities: un’altra implementazione di LINQ fatta per parlare con l’ADO.NET Entity Framework (EF). Sia l’EF che LINQ to Entities sono attualmente in Beta 3. L’EF è un framework che consentirà agli sviluppatori di lavorare con un maggior livello di astrazione; cioè uno sviluppatore si concentrerà solo sul modello concettuale proprio del modello Entità-Relazione, in maniera indipendente dallo storage sottostante sia esso SQL Server o un altro database.

LINQ to Entities realizza un VERO ORM, supportando quindi relazioni molti-a-molti e generalizzazioni e separando il mapping da relazionale a oggetti in file xml separati, in modo da non inquinare l’interfaccia delle classi generate. Come detto, siamo in una versione non completamente matura e per questo è stato deciso di posticipare l’uscita di questa branca a circa sei mesi dopo l’uscita di Visual Studio 2008 e perciò l’infrastruttura attualmente presente potrebbe subire forti cambiamenti.

Maggiori informazioni sulle differenze tra LINQ To SQL e LINQ To Entities sono riportate nel post di Kevin Hoffman.

Posted in .net | 1 Comment »

.NET 3.5: le Novità del Linguaggio C#

Posted by Ricibald on 6th March 2008

Nella specifica c# 3.0 sono riportate le principali novità nel linguaggio C#. Tranquilli, la maggior parte sono solo utile zucchero sintattico.

Automatic Properties

Invece di scrivere:

public class Persona {
    private int _matricola;
    public int Matricola {
        get {
            return _matricola;
        }
    }
    private string _nome;
    public int Nome {
        get {
            return _nome;
        }
        set {
            _nome = value;
        }
    }

    public Persona(int matricola) {
        _matricola = matricola;
    }
}

Ora scriveremo:

public class Persona {
    public string Matricola { get; private set; }
    public string Nome { get; set; }
    public Persona(int matricola) {
        this.Matricola = matricola;
    }
}

Il compilatore crea automaticamente i corrispondenti campi privati e le relative implementazioni get/set.

Nel caso però in cui il metodo get/set debba essere personalizzato, allora è necessario ricorrere al vecchio stile di definizione delle proprietà.

Object Initializer

Invece di scrivere :

Persona persona = new Persona(15);
persona.Nome = "Riccardo";
persona.Anni = 25;

Scriveremo:

Persona persona = new Persona(15) { Nome = "Riccardo", Anni = 25 };

Rappresenta quindi solamente un modo per scrivere in modo compatto il codice precedente. Non deve quindi essere visto come un modo per
rimpiazzare la logica dei costruttori
.

Collection Initializers

Un Object Initializer particolare appartiene ai tipi ICollection che supportano i Collection Initializer:

Persona persona = new Persona(15) { Nome = "Riccardo", Anni = 25 };
ICollection
<Persona> personas = new List<Persona>
 { persona };

Sinceramente mi sembra solo un modo per uniformare il popolamento delle collezioni al popolamento degli array.
Infatti, per avere lo stesso comportamento sarebbe stato sufficiente aggiungere un costruttore con la signature:

public List(params T[] ts)

e non sarebbe stato necessario inserire ulteriore sovrabbondante “zucchero sintattico”.

Partial Methods

Le classi scritte dal designer sono classi parziali. Ma se si vogliono definire dei punti estensibilità per la classe autogenerata (OnAction()) avremmo bisogno non di una classe parziale, ma di una classe padre da cui eredita la nostra classe. Questo non è conveniente poiché ci leghiamo definitivamente a una classe padre. Per ovviare a questo problema sono stati definiti i metodi parziali, un modo per definire opzionalmente dei metodi nella nostra classe.

Quindi se nel designer abbiamo:

public partial class Studente {
    private int _matricola;
    public int Matricola {
        get { return _matricola; }
        set {
            this.OnMatricolaChanging(value);
            _matricola = value;
    }
    partial void OnMatricolaChanging(int m);
}

Mentre nella nostra classe avremo:

public partial class Studente {
    partial void OnMatricolaChanging(int m) {
        if (m.ToString().Length == 5) {
            throw new Exception("Matricola non valida!");
        }
    }
}

Lambda Expressions

Ricordate il post dove parlavo della potenza dei delegati anonimi?
Bene, questo è altro zucchero sintattico per scrivere in maniera compatta delegati anonimi. Immaginiamo quindi di aver definito il seguente delegato anonimo e il metodo che ne fa uso:

public class SearchFunctions {
    public delegate bool SearchFunction<T>(T arg);
    public static T Search<T>(IEnumerable<T> c, SearchFunction<T> s);
}

Verrà invocato nel seguente modo:

ICollection
<Persona> personas = new List
<Persona> { new Persona(15), new Persona(23) };
Persona p = SearchFunctions.Search(personas, delegate(Persona personaDaVerificare) {
    return personaDaVerificare.Matricola == 23;
});

Tramite le Lambda Expressions, che si basano sul Lambda Calcolo, è possibile esprimere in modo compatto l’espressione:

Persona p = SearchFunctions.Search(personas, personaDaVerificare => personaDaVerificare.Matricola == 23);

Si noti come non è stato inserita alcuna informazione sul tipo della variabile “personaDaVerificare”: tale tipo verrà automaticamente dedotto.

Extension Methods

Ora arriviamo ai due punti per me più discussi, che (secondo me) non hanno senso di esistere a meno di eccezioni molto particolari.
Gli Extension Method consentono di estendere le funzionalità del framework. Si consideri ad esempio:

string email = "prova"
if ( EmailValidator.IsValid(email) ) { /* Implementazione */ }

Tramite gli Extension Method possiamo aggiungere funzionalità direttamente dentro la classe string:

public static class MyExtensions
{
    public static bool IsValidEmailAddress(this string s) { /* ... */ }
}

Si noti il “this” davanti al parametro: indica che vado ad aggiungere un metodo alla classe string.
Si possono invocare tramite:

using MyExtensions;

/* ... */
string email = "prova"
if ( email.IsValidEmailAddress() ) { /* Implementazione */ }

Questo utilizzo degli Extension Method lo considero una specie di enorme bug: capire l’organizzazione di un codice scritto in questa maniera diventa un incubo. Non posso mica conoscere tutti i metodi di tutte le classi, quindi se leggo codice scritto da altri dovrei quantomeno assumere che il codice proveniente da classi di .NET siano funzionanti o no? In questo modo sono costretto a ispezionare tutti i riferimenti alla ricerca di un eventuale Extension Method prima di dire “ok, iniziamo”. E poi era così brutto richiamare l’EmailValidator? A me non sembrava…

Però su una cosa sono utili: non prevedono di conoscere l’EmailValidator: le funzionalità sono già fornite come built-in del tipo. Risulta molto comodo quindi, nel caso in cui queste funzionalità sono state scritte anche anni fa (e chi se le ricorda più…). Se si creano extension method con lo stesso namespace del tipo che estendiamo avremo funzionalità aggiuntive “sempre” disponibili, e non utilizzabili solo se la “memoria dello sviluppatore” lo permette…

L’unico caso (secondo me) in cui risulta utile è quando il tipo restituito dall’Extension Method è lo stesso del tipo modificato:

public static T MyExtensionMethod(this T t /*, ... */)

In questo caso risulta comodo, poiche’ assume il ruolo di decoratore o filtro. Se infatti creiamo gli Extension Method:

public static class MyExtensions
{
    public static int MescolaCifre(this int i) { }
    public static int TogliSegno(this int i) { }
    public static int RendiDivisibilePer(this int i, int d) { }
}

Si può quindi utilizzare nel seguente modo:

using MyExtensions;

/* ... */
int i = 58935728957.MescolaCifre().TogliSegno().RendiDivisibilePer(5);

Anonymous Types

L’ultimo da discutere sono i tipi anonimi. In pratica invece di scrivere:

string nome = "Riccardo";
int matricola = 15;
int anni = 25;
nome = nome.ToUpper();
matricola++;

posso scrivere:

var nome = "Riccardo";
var matricola = 15;
var anni = 25;
nome = nome.ToUpper();
matricola++;

e il tipo viene “magicamente” dedotto dal compilatore.

Spero direte: “E allora? Non è un evoluzione, ma un tornare indietro“. Vero! Ma esistono casi particolari in cui ha senso.

L’unico utilizzo a mio parere giustificato dei tipi impliciti stà:

  • nell’uso delle funzioni lambda dove di fatto avviene una tipizzazione implicita
  • dove non ha senso parlare di tipi: ad esempio in tuple restituite da una query sql. In questo caso, viceversa, risulta una forzatura definire un tipo a tutti i costi, solo per avvolgere valori

Posted in .net | 9 Comments »

L’operatore ?? in C#

Posted by Ricibald on 6th March 2008

Un utile operatore che è stato introdotto nella versione 3.0 del framework è il ??.

Semplicemente, il seguente codice:

string result = message ?? "Il messaggio e' nullo";

Imposta message in result solo se il messaggio è presente, altrimenti restituisce “Il messaggio è nullo“.

Un operatore semplice, niente di nuovo, ma molto comodo nello scrivere di tutti i giorni…

Posted in .net | 2 Comments »