Quando mi trovo a parlare con altri sviluppatori, la prima cosa che consiglio è definire il meglio possibile un buon
Domain Model dell'applicazione, in termini di Classi, Funzionalità,Comportamenti e Architettura dell'applicazione, per avere dei benefici durante lo sviluppo e l'inevitabile "ondata" di richieste successive all'analisi...
Per quanto riguarda la definizione degli oggetti .net ci mette a disposizione dei tool fantastici
Entity Framework,
LinqToSql , adesso con
Visual Studio 2010 anche diagrammi UML o semplicemente il Class Designer. A volte però per necessità di "personalizzazione" o cmq se vogliamo dare una "dinamicità spinta" dell'applicazione, non si riesce a definire un oggetto completo di tutte le proprietà che possono servire...alcune possono dover essere gestite in fase di configurazione o di funzionamento, perchè dipendono dall'esigenza "verticale" dell'utilizzatore.
In questa situazione c'è bisogno di un oggetto che permetta questo dinamismo, le 2 tecniche che mi sono trovato ad usare sono state:
Dotarlo di una Collection di un oggetto che identificherà un campo del database (il cosiddetto "CampoDinamico") per cui una proprietà "List<CampoDinamico>" che poi da codice viene letta|scritta da codice:
public class CampoDinamico
{
public string Nome { get; set; }
public string Alias { get; set; }
public object Valore { get; set; }
...
}
public class Utente
{
...
public List<CampoDinamico> CampiDinamici { get; set; }
}
I controlli che visualizzano i dati, ad esempio le griglie diventano "dinamici" nel senso che si aspettano la presenza di questa collection e vanno in discovery di questi campi, ad esempio le query sul database poi vengono generate dinamicamente in base a questi.
La comodità di questa tecnica è che si conosce a priori il tipo "CampoDinamico" quindi diventa più facile estenderlo con le ulteriori proprietà che possono essere utile (ReadOnly, Identity etc...)
Di contro abbiamo il fatto che il codice si complica un po' nel senso che devo accedere a quella proprietà e il binding di componenti diventa difficile se non si usa WPF...
La seconda tecnica, e a mio avviso forse anche la migliore, è l'Extender, ossia dare la possibilità di definire delle proprietà a runtime tramite Dictionary<string,object> in cui la stringa corrisponde al nome della proprietà, e invece quello che torna è il valore (chiaramente in object per avere ancora maggiore flessibilità):
public class Utente
{
public int ID { get; set; }
public string Descrizione { get; set; }
private Dictionary<string, object> proprieta = new Dictionary<string, object>();
public object this[string nome]
{
get {
if (proprieta.ContainsKey(nome))
return proprieta[nome];
else
return null;
}
set {
if (proprieta.ContainsKey(nome))
proprieta[nome] = value;
else
proprieta.Add(nome, value);
}
}
//--- per enumerare
public IEnumerable<string> Keys { get { return proprieta.Keys; } }
}
Anche qui c'è bisogno di un codice che faccia il discovery, ma diventa leggermente più semplice, infatti portando fuori la proprietà "Keys" del mio Dictionary sottostante, basta un semplice foreach:
//--- discovery di che proprietà ha l'oggetto
Utente utente = utenti.First();
foreach (string chiave in utente.Keys)
{
....
La cosa simpatica è che Silverlight supporta il binding per questa tecnica, ossia possiamo dire di agganciarsi a quella proprietà definendone il nome tra parentesi quadre "[NomeProprieta]":
<ListBox x:Name="listBox" Margin="16,43,216,93">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding [codice]}" />
<TextBlock Text="{Binding [eta],FallbackValue=-}" />
<TextBlock Text="{Binding ID}" />
<TextBlock Text="{Binding Descrizione}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
(Notare che è disponibile anche la proprietà "FallbackValue" che sta a significare "se non riesci a fare il binding, visualizza questo valore")
Anche qui posso generare una griglia dinamica, ed associare il Binding con le parentesi quadre:
//--- aggiungo le colonne
Utente ut = utenti.First();
foreach (var k in ut.Keys)
{
utentiGrid.Columns.Add(new DataGridTextColumn() {
Binding = new Binding("[" + k + "]"),
Header = k,
Width = DataGridLength.Auto
});
}
//--- bindo la collection
utenteGrid.ItemsSource = utenti;
A mio avviso le proprietà dinamiche degli oggetti non sono esigenze che si verificano in ogni progetto, ma se qualche cliente ce lo chiede,
almeno sappiamo che è fattibile abbastanza facilmente...in Silverlight poi è anche utilizzabile nel meccanismo di Binding.