A volte, il codice "riflesso" con il Reflector, ci mette su false piste. Qualcuno, guardando per esempio l'implementazione dei singleton delle classi factory dei provider ADO.NET, tramite il Reflector, potrebbe erroneamente pensare che inizializzare esplicitamente un campo statico nel costruttore statico fosse una best practice:
// snippet 1
// codice tramite il Reflector
namespace System.Data.SqlClient
{
public sealed class SqlClientFactory : DbProviderFactory
{
public static readonly SqlClientFactory Instance;
// codice non ottimizzato
static SqlClientFactory()
{
Instance = new SqlClientFactory();
}
private SqlClientFactory() { }
// ...
}
}
E invece, il codice "reale" è questo:
// snippet 2
namespace System.Data.SqlClient
{
public sealed class SqlClientFactory : DbProviderFactory
{
// codice ottimizzato
public static readonly SqlClientFactory Instance = new SqlClientFactory();
private SqlClientFactory() { }
// ...
}
}
Come ci si accorge? Dal flag IL beforefieldinit con cui è decorata la classe:
.class public auto ansi sealed beforefieldinit System.Data.SqlClient.SqlClientFactory extends System.Data.Common.DbProviderFactory{}
Lo snippet 1 non genera il flag beforefieldinit, lo snippet 2 invece sì - purtroppo il Reflector non è ancora capace di fare la differenza tra i due snippet.
La linea guida è (FDG, p. 131):
"Consider initializing static fields inline rather than explicitly using static constructors, as the runtime is able to optimize performance of types that don't have an explicitly defined static constructor."
So che la questione del beforefieldinit non è per nulla nuova (in questo post di Simone potete trovare anche altri link interessanti a riguardo) ma quello che volevo sottolineare qui è solo l'invito a riflettere un po' di più sugli idiom che notiamo tramite Reflector.