Ho letto il post di Lanny stamattina e ho deciso che probabilmente era il caso di postare un esempietto su come sia preferibile lavorare con la reflection per evitare i problemi più comuni. L'esempio di Lanny funziona ed è utile per capire come funziona la reflection, ma dovendo lavorare con essa è opportuno fare affidamento su una serie di classi belle e pronte che il framework mette a disposizione. Oltre a snellire il lavoro eliminando la necessità di riscrivere del codice che è già perfettamente funzionane, consentono soprattutto di avere un modo affidabile di operare conversioni di tipo senza incorrere nei comuni errori dovuti alla globalization. Ecco uno spezzone di codice commentato che mostra come creare un tipo, settarne le proprietà e operare delle conversioni da stringa a data utilizzando le comodissime TypeDescriptor e TypeConverter:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;

namespace TestTipi
{
    
class Program
    {
        
static void Main(string[] args)
        {
            
// ottengo il riferimento al tipo da istanziare
            
Type personType = 
                Type.GetType("TestTipi.Person, TestTipi");
            
            
// creo una istanza del tipo
            
object p = 
                TypeDescriptor.CreateInstance(
null, personType, nullnull);
            
            
// ottengo una collection delle property dell'istanzaa
            
PropertyDescriptorCollection personProperties = 
                TypeDescriptor.GetProperties(p);
            
            
// setto FirstName
            
PropertyDescriptor firstName = 
                personProperties.Find("FirstName", 
false);
            firstName.SetValue(p, "Andrea");

            
// setto LastName
            
PropertyDescriptor lastName = 
                personProperties.Find("LastName", 
false);
            lastName.SetValue(p, "Boschin");

            
// setto Birthday
            
PropertyDescriptor birthDay = 
                personProperties.Find("Birthday", 
false);
            TypeConverter converterToDate = 
                TypeDescriptor.GetConverter(birthDay.PropertyType);
            birthDay.SetValue(
                p,
                converterToDate.ConvertFromString(
                    
null
                    CultureInfo.CreateSpecificCulture("en-US"), 
                    "10/27/1968"));

            
// dump sulla console
            
Console.WriteLine(p);
            Console.ReadLine();
        }
    }

    
/// <summary>
    /// 
classina di test
    
/// </summary>
    
class Person
    {
        
private string firstName;
        
private string lastName;
        
private DateTime birthday;

        
public string FirstName
        {
            
get return firstName; }
            
set { firstName = value; }
        }

        
public string LastName
        {
            
get return lastName; }
            
set { lastName = value; }
        }

        
public DateTime Birthday
        {
            
get return birthday; }
            
set { birthday = value; }
        }

        
public override string ToString()
        {
            
return string.Format(
                "{0} {1} ({2})", 
                
this.FirstName, 
                
this.LastName, 
                DateTime.Now.Year - 
this.Birthday.Year);
        }
    }
}

Due note rapide sull'esempio: per creare l'istanza di un tipo è opportuno evitare l'uso di Assemply.LoadFrom() ovunque possibile. piuttosto è preferibile usare come nell'esempio la Type.GetType() passando il nome completo del tipo includendo anche version, culture e publickeytoken qualora l'assembly si trovi in GAC o sia firmato. Usare il riferimento al nome del file non è una buona politica perchè così facendo si esclude tutto il meccanismo di ricerca di fusion. La Type.GetType() è in grado di lavorare perfettamente anche con gli assembly autogenerati a patto che vengano messi in una directory che si trova nell'ambito del probing di fusion.

Secondo: convertire da stringa a qualsiasi tipo e viceversa è un'attività insidiosa tanto che nel framework ci sono svariati errori proprio su questo argomento. Meglio perciò usare la TypeConverter che per inciso è un grado di fare conversioni anche su tipi particolari come ad esempio le Unit. TypeDescriptor ha un bellissimo metodo GetConverter() che è in grado di istanziare l'opportuno convertitore semplicemente passandogli il tipo di destinazione. Okkio quindi che la Culture va passata SEMPRE!

Infine, attenzione ai null. Io nel post non ho messo alcun controllo per non risultare chilometrico, ma e' evidente che ogni volta che chiediamo di istanziare un tipo, un assembly, un convertitore, etc... dobbiamo verificare opportunamente che tutto sia andato a buon fine.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Tipi, proprietà e reflection