aprile 2005 Blog Posts
Sapevate che Krzysztof Cwalina è anche uno dei più veloci nuotatori polacchi? E un'altra cosa carina, ha fatto la tesi di laurea con una professoressa italiana.
Ve ne siete probabilmente accorti di questo commento nei vostri file IL disassemblati:
// --- The following custom attribute is added automatically, do not uncomment -------// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool, bool) = ( 01 00 00 01 00 00 )
Per farlo sparire basta compilare con le opzioni /debug- ("do not emit debugging information") e /o+ ("enable optimizations").
Interessante è il fatto che se non compilate con queste opzioni un assembly decorato con:
[assembly: System.Diagnostics.Debuggable(false, false)]
cioè i parametri isJITTrackingEnabled e isJITOptimizerDisabled a false, ottenete in C# l'errore CS0647:
error CS0647: Error emitting 'System.Diagnostics.DebuggableAttribute' attribute-- 'Assembly custom attribute 'System.Diagnostics.DebuggableAttribute' was specified multiple times with...
In dasm.cpp, che fa parte dell'implementazione dell'ildasm del Rotor, potete trovare questa simpatica label:
if(g_pPELoader) goto DumpTheSucker;
Beh, dopo il punto e virgola dello statement, aggiungerei un trattino e una parentesi chiusa ;-)
Pensavate che non si possa scrivere una classe in C# che non derivi da nessun'altra classe, vero? :-) Provate a compilare questo codice:
namespace System{ class Object {}}
Passando l'assembly all'ildasm, notiamo due cose "strane":
.namespace System{ .class private auto ansi beforefieldinit Object { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 0 br.s here here: ret } }}
è sparita la clausa extends [mscorlib]System.Object (dobbiamo prendere sul serio il commento "note that class flags, 'extends' and 'implements' clauses are provided here for information only"? - vedi anche questo altro mio post);
il costruttore non chiama il costruttore della...
Dopo una registrazione gratuita è possibile scaricare questo interessantissimo libro (311 pagine), appena uscito:
G. Nutt, "Distributed virtual machines: inside the Rotor CLI", Pearson Addison Wesley (2005)
(Aggiornamento 17/04/05): Scopro adesso che Marco Russo l'aveva già segnalato quasi un anno e mezzo fa, quando il libro era ancora "in fase di scrittura".
E' interessante notare che il compilatore Visual C# genera per gli snippet a sinistra lo stesso codice IL degli snippet a destra:
class Foo{ static void DoSomething() { if (true) {} }}
class Foo{ static void DoSomething() {}}
class Foo{ static void DoSomething() { if (false) {} }}
class Foo{ static void DoSomething() { goto here; here:; }}
Quando l'espressione booleana è sempre true, il compilatore sostituisce l'if con il ramo then, mentre quando l'espressione booleana è sempre false, il compilatore sostituisce l'if con un salto incondizionato al ramo else. Nel primo caso si genera solo il codice per il ramo then, mentre nel secondo...
In SLAR alla pagina 389 c'è scritto che:
"This class is used only by the system; applications cannot create instances of the System.Security.SecurityElement type"
Questa affermazione non è vera: la classe SecurityElement è in sostanza un parser XML leggero (sa parsare solo elementi, attributi e testo) e può essere utilizzata come qualunque altra classe. Un bellissimo esempio è mostrato in questo post di Shawn Farkas sulla trasformazione SecurityElement <-> XmlElement. Lo dimostra anche l'esempio che si trova in SLAR nella stessa pagina (la classe Samples.SecurityElementSample).
class Foo{ static Foo() { System.Console.WriteLine("Ciao!"); } static void Main(){}}
Questo innocente snippet stampa a console Ciao! pur avendo un Main vuoto. Per evitare stranezze di questo tipo, ho tirato fuori una best practice per i Main: evitare di avere un costruttore di tipo nella classe che contiene l'entry point.
using System;using System.Diagnostics;class Foo{ [Conditional("X")] static void Main() { Main(); Console.WriteLine("Ciao!"); }}
Vi aspettate:
A. stampa Ciao! a console
B. non stampa niente
C. errore StackOverflowException a runtime
Le vostre risposte con le dovute spiegazioni lasciatele nei commenti, fino a mercoledì sera.
Visto che non ricevo tutti i giorni una mail da Paul Vick, la posto :-)
Adrian,
Thank you so much for your email! You are correct that the examples are wrong... it looks like they somehow slipped through our editing process!I'll make sure that they are corrected in the next version of the specification, which should be coming out with Beta2 of VB 2005.
Thanks so much for the bug reports!
Paul
La mail conferma i bug segnalati in un post precedente. Gli indirizzi MSDN degli esempi errati sono:
9.2.6 Event Handling
9.6.2 WithEvents Variables
10.5.1 RaiseEvent Statement
Dopo il post di ieri sulla classe PrivateImplementationDetails e sugli array initializer in C#, ho continuato a giocare un po' e guardate cosa ho combinato...
using System;using System.Reflection;using System.Runtime.InteropServices;class Foo{ static void ContainsLocalArrayInitializer() { int[] a = new int[3]{1, 2, 3}; } static int[] GetLocalArrayInitializerOfSomebodyElse() { int[] a = new int[3]; IntPtr buffer = Marshal.AllocHGlobal(12); Marshal.StructureToPtr(Assembly.GetExecutingAssembly().GetModules()[0]. GetType("<PrivateImplementationDetails>").GetField("$$method0x6000001-1", BindingFlags.NonPublic | BindingFlags.Static). GetValue(null), buffer, true); Marshal.Copy(buffer, a, 0, a.Length); Marshal.FreeHGlobal(buffer); return a; } static void Main() { int[] stolenArray = GetLocalArrayInitializerOfSomebodyElse(); foreach(int element in stolenArray) { Console.WriteLine(element); } }}
Lo snippet stampa a console gli elementi con cui è stato inizializzato l'array locale di...
Nell'ultimo quiz (#47) è stato l'array initializer:
int[] a = new int[3]{1, 2, 3};
a generare la classe '<PrivateImplementationDetails>' di cui proverò a parlere in questo post.
Cioè, cambiando l'array initializer con:
int[] a = new int[3];a[0] = 1;a[1] = 2;a[2] = 3;
lo snippet del quiz avrebbe stampato a console abc (la risposta B e non C).
Nel nostro caso, il codice IL generato per questa classe non documentata è:
.class private auto ansi '<PrivateImplementationDetails>' extends [mscorlib]System.Object{ .class explicit ansi sealed nested private '$$struct0x6000001-1' extends [mscorlib]System.ValueType { .pack 1 .size 12 } .field static assembly valuetype '<PrivateImplementationDetails>'/'$$struct0x6000001-1' '$$method0x6000001-1' at D_00002050}.data D_00002050 = bytearray (01...
using System;using System.Reflection;class Foo{ public Foo() { int[] a = new int[3]{1, 2, 3}; foreach(int i in a) { Console.Write(i); } Console.WriteLine(); } static void Main() { try { Activator.CreateInstance(Assembly.GetExecutingAssembly().GetTypes()[2]); } catch(IndexOutOfRangeException e) { Console.WriteLine("abc"); } }}
Cosa stampa a console e perché?
A. 123
B. abc
C. non viene stampato nulla
La frase del giorno: "due anni in Garabagna, circa altrettanti nel paese della Magia, un po' meno a Poddema" - Henri Michaux