Generare classi a runtime con C# e la Reflection

di Roberto Albano, in .NET Framework,

Già negli anni '90 Delphi metteva a disposizione le RTTI (Run Time Type Information), un concetto introdotto con C++ per gestire le informazioni sui tipi, anche se erano altamente sconsigliate per problemi di retro compatibilità, dato che le classi cambiavano sempre ad ogni nuova versione del linguaggio. In .NET vi è la Reflection, che in pratica rappresenta la stessa cosa delle RTTI, ideati con un concetto stabile di retro compatibilità, e con una potenza superiore, oserei dire talvolta anche imbarazzante. Infatti si possono raggiungere tali livelli di astrazione sia sulle classi che sulle istanze, che possiamo addirittura arrivare a creare classi a runtime, istanziarle e usarle. In questo articolo parliamo proprio di questo.

Le classi di riferimento

Per esaminare le possibilità offerte dalle classi presenti nella Reflection, faremo riferimento al namespace System.Reflection, mentre per la generazione dinamica avremo bisogno di alcune classi che sono posizionate nel namespace System.Reflection.Emit.

In quest'ultimo namespace possiamo trovare infatti diverse classi Builder, come per esempio:

  • MethodBuilder;
  • PropertyBuilder;
  • FieldBuilder;
  • TypeBuilder;
  • ... e tante altre ancora.

Come si capirà dal nome, si tratta di classi che "costruiscono" un metodo, una proprietà, un attributo e ovviamente anche un tipo. Nella costruzione dell'oggetto a loro affidato, queste classi consentono la definizione di nomi, visibilità, parametri, ovvero tutto quello che noi normalmente scriveremmo a design-time, può essere fatto (con un pò di pazienza) anche da codice per essere generato a run-time.

Una volta definite le proprietà, i metodi e le classi che vogliamo creare a runtime, è necessario anche compilare il codice, ovvero ottenere il codice IL (Intermediate Language) che ci consente di eseguire il nostro nuovo codice.

Il nostro scenario

Per il nostro esempio ipotizziamo un contesto di lavoro in cui venga utilizzato un modello dati realizzato con LINQ2SQL, dove ci si trovi nella situazione di dover eseguire delle ricerche su questo DataContext, facendosi ritornare i risultati in un "formato" stabilito di volta in volta, in funzione di alcuni fattori.

Utilizzeremo le classi dei namespace visti prima per definire ex-novo una classe, nel nostro caso facendola partire da una già esistente, ovvero filtrando le proprietà di una entity LINQ2SQL per ottenerne un'altra. Nelle potenzialità di queste classi in realtà, è prevista anche la scrittura di codice a runtime, operazione non molto distante da quello che vedremo in questo esempio, ma che comunque non tratteremo qui. Il progetto di esempio sarà una console application e il database sarà AdventureWorks, disponibile qui. Da questo database creiamo (per nostro uso e consumo) un DataContext con solo due tabelle, come vedete nell'immagine che segue:

Modello oggetti delle due tabelle di esempio

Il nostro scopo è quello di cercare nei prodotti quelli che contengono nel "Name" una determinata stringa o parte di stringa, e farci tornare una entità costruita ad hoc con campi specifici.

Dato che il nostro scenario è veramente molto semplice, possiamo ipotizzare che tutti gli articoli che rappresentano biciclette appartengano a categorie che abbiano all'interno del loro nome la parola "bike", per cui possiamo distinguere le biciclette dagli altri prodotti semplicemente con questo tipo di ricerca. Una volta fatta questa suddivisione vogliamo creare una classe per le "bike" e una classe per le "non-bike".

4 pagine in totale: 1 2 3 4
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti