Quando si dice: "Una classe con gli Attributi"

A volte capita di studiare un argomento e, successivamente, di "dimenticarlo" per scarso utilizzo, salvo poi tornare alla memoria quando, per un motivo qualunque, ci si sbatte la testa in un progetto reale. Ieri mi è capitato proprio questo quando, implementando una libreria di test da dare in pasto ad NUnit, stavo implementando un test che verificava la serializzabilità di una classe... "Bene", mi sono detto: "Adesso implemento due test, che chiamerò IsSerializable e CanBeSerialized che verificheranno rispettivamente l'avvenuta decorazione con l'attributo SerializableAttribute e l'effettiva possibilità di serializzare una istanza". Pronti-via, ho scritto il normale codice con il quale è possibile recuperare gli attributi utilizzati per decorare una classe, adattandolo alla ricerca dell'attributo richiesto:

Type theType = typeof(ValidationRule);
SerializableAttribute[] attributes = (SerializableAttribute[]) theType.GetCustomAttributes(typeof(SerializableAttribute), true);

Con un po' di sorpresa, ho constatato che l'array non conteneva elementi, anche se la classe ValidationRule era effettivamente decorata con SerializableAttribute. Ho quindi creato un piccolo progettino per testare il "problema", definendo due classi, rispettivamente un attributo ed una "cavia":

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MyCustomAttribute : System.Attribute
{
    public string Message=string.Empty;
}

[MyCustom(Message="Custom attribute usage")]
[Obsolete("Oltre che obsoleta, è addirittura inutile.")]
[PrincipalPermission(SecurityAction.Demand)]            //richiede "using System.Security.Permissions"!
[Serializable()]
public class Car
{
}

Una bella compilazione (effettuata sia con il compilatore commerciale, sia con qllo di Rotor), e via a sbirciare il codice con ILDASM:
Decompilazione con ILDASM: SerializableAttribute è mappata direttamente su IL

Vedete la parolina serializable lì in alto? :-) Cosa significa? In poche parole, significa che non tutti gli attributi sono "compilati" allo stesso modo o, se preferite, che il compilatore conosce "a priori" alcuni attributi. Mosso dalla curiosità, mi sono detto: "perchè non controllare nel sorgente del compilatore?". A questo punto, grazie al (paziente) supporto del prode Gianluca Carucci ho implementato il pattern multithreaded geeking, ossia abbiamo cercato in parallelo sia nel sorgente di Mono, sia in qllo di Rotor, ed il risultato è decisamente interessante: spulciando tra i sorgenti di quest'ultimo, infatti, si trova il file custattr.cpp, che contiene due sezioni interessanti, la prima delle quali contiene la lista degli attributi "Custom-per-finta" (poi capiremo il motivo di questa definizione) conosciuti by design:
La lista degli attributi conosciuti dal compilatore: c'è anche Serializable! :-)
 
Più in basso, infine, c'è il blocco switch-case che testa gli attributi conosciuti:
 
Il compilatore testa la presenza di Serializable

Come riportato dal file di documentazione csharp_incremental.html incluso nella documentazione di Rotor, esistono 3 famiglie di attributi: Custom, Pseudo-Custom (Serializable fa parte di questi) e Compiler-Generated. Risulta ora evidente il motivo per il quale Reflection fallisce su alcuni attributi, essendo in grado di rilevare solo qlli di tipo "Custom".
Feature o bug? Sicuramente è una feature, anche se ne avrei fatto volentieri a meno: se è vero, infatti, che è possibile sopperire al problema nel caso dell'attributo SerializableAttribute semplicemente testando la proprietà IsSerializable della classe System.Type, non è però assicurabile la possibilità di recuperare le informazioni di tutti gli attributi non custom. Per esempio, per esplicita ammissione di un membro del team di sviluppo del CLR, non è attualmente possibile recuperare le informazioni relative agli attributi dedicati alla Code Access Security. Francamente, avrei preferito un approccio più omogeneo...

E con Whidbey? Appena ho un momento libero, ci provo... :-)

Microsoft "depreca" il SOAP Toolkit

Suscitando in me sorpresa e disappunto, Microsoft ha annunciato che il SOAP Toolkit è deprecato a favore del .NET Framework. Il disappunto non è (ovviamente) dovuto alla raccomandazione di usare le classi del namespace System.Xml (il framework è sempre benvenuto!), bensì al fatto che il SOAP Toolkit è una valida soluzione al problema rappresentato dalla necessità di consumare web services in applicazioni VB6 o ASP. Fortunatamente la "tagliola" scatta solo il primo luglio 2004, così non mi sentirò in colpa quando (a febbraio) parlerò di questa libreria durante i miei webcast Microsoft; sinceramente, comunque, non credo che smetterò di usare il toolkit per le mie esigenze professionali... :-)

«gennaio»
domlunmarmergiovensab
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567