Invocare un Metodo con una Culture Personalizzata
Posted by Ricibald on 7th February 2008
Per formattare le date o i numeri in un certo modo si possono utilizzare le tecniche di formattazione.
Quindi, se ad esempio vogliamo esprimere la data in un formato particolare, possiamo utilizzare:
DateTime date = DateTime.Now;
string format = date.ToString("MM/dd/yyyy g");
Per maggiore flessibilità possiamo immaginare di inserire il formato in una chiave di configurazione e il gioco è fatto.
Ma ora immaginiamo che ci arrivi una nuova richiesta dal nostro fido cliente:
Voglio i numeri a virgola mobile formattate come “xx.yy”.
Ora, dovremmo quindi andare a modificare tutti i double come:
double d = 2.2;
string format = d.ToString("00.00");
Il problema è quindi che le modifiche ai formati non sono sotto controllo. Esistono due modi per mantenerli sotto controllo, utilizzando le CultureInfo:
- invocare dove possibile
ToString(IFormatProvider), passando una CultureInfo creata al momento dell’inizializzazione- ma richiede un’accortezza di chi scrive codice
- …e una bella scocciatura…
- specificare la CultureInfo dell’assembly nel file di configurazione
- deve essere o standard o creata appositamente e registrata
- chi la crea? chi la registra?
- vincolo tutto il progetto ad utilizzare quella CultureInfo: come ripristinare il comportamento originario?
- deve essere o standard o creata appositamente e registrata
Dall’altra parte è vero che la CultureInfo del thread corrente potrebbe essere impostata come si vuole, ma bisogna anche fare i conti con il multi-threading, specialmente vero in applicazioni a interfaccia grafica o web.
Bisognerebbe quindi:
creare un thread con l’unico scopo di isolare il cambiamento di CultureInfo
Si vuole quindi rendere disponibile una funzione che in modo generico faccia questo:
class BilancioCreator {
public Bilancio CreaBilancio(int annoBilancio)
{
return CustomCultureInfoInvoker.InvokeMethod<Bilancio>(new CustomCultureInfo(), delegate()
{
return CreaBilancioImpl(annoBilancio);
});
}
private Bilancio CreaBilancioImpl(int annoBilancio)
{
string data = DateTime.Now;
Bilancio result = new Bilancio(data.ToString());
result.CalcolaBilancio(annoBilancio);
return result;
}
}
class CustomCultureInfo : CultureInfo
{
public CustomCultureInfo()
: base("en-US")
{
this.NumberFormat.CurrencyDecimalSeparator = ".";
this.NumberFormat.CurrencyDecimalDigits = 0;
this.NumberFormat.CurrencyGroupSeparator = "";
this.NumberFormat.CurrencyNegativePattern = 5;
this.NumberFormat.CurrencySymbol = "";
this.NumberFormat.NumberDecimalDigits = 0;
/* Il DateTime.ToString combina ShortDatePattern con LongTimePattern */
this.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
this.DateTimeFormat.LongTimePattern = "";
}
}
Si mette quindi a disposizione il codice che consente questo, per chiunque ne fosse interessato.
public static class CustomCultureInfoInvoker
{
public delegate T Method<T>();
public static T InvokeMethod<T>(CultureInfo culture, Method<T> method)
{
Exception exceptionThread = null;
T result = default(T);
Thread customCultureThread = new Thread(delegate()
{
try
{
result = method.Invoke();
}
catch (Exception ex)
{
exceptionThread = ex;
}
});
customCultureThread.CurrentCulture = culture;
customCultureThread.CurrentUICulture = culture;
customCultureThread.Start();
customCultureThread.Join();
/* Rilancia eventuali errori */
if (exceptionThread != null)
{
throw new Exception("Errore: " + exceptionThread.Message, exceptionThread);
}
return result;
}
}
Notare che per i valori “decimal” il discorso è un po’ diverso, poiché in questo caso la CultureInfo non consente di fare proprio tutto. Per questo si veda il precedente post per cambiare blocchi di valori dello stesso tipo.
Posted in .net | No Comments »