Web Log di Adrian Florea

"You know you've achieved perfection in design, not when you have nothing more to add, but when you have nothing more to take away." Antoine de Saint-Exupery
posts - 440, comments - 2715, trackbacks - 3944

My Links

Archives

Post Categories

Image Galleries

.RO Blogs

.RO People

.RO Sites

Blogs

Furls

Links

vinCitori

Carillon .NET

Vita da service pack

Ho scoperto una cosa a mio parere strana: un metodo (System.Web.UI.WebControls.ParameterCollection.Add(String, DbType, String)) che esiste solo nelle versioni service pack del framework .NET (2.0 SP2, 3.0 SP2, 3.5 SP1) ma non nelle versioni "normali". Mi chiedo come mai se il metodo e' stato introdotto in .NET 2.0 SP2, l'abbiano tolto dalle .NET 3.0 e .NET 3.0 SP1 per reintrodurlo nella .NET 3.0 SP2 per poi toglierlo di nuovo dalla .NET 3.5 e finalmente reintrodurlo nella .NET 3.5 SP1???... [OT] Per i tanti amici milanesi: sono a Milano dall'8 di marzo e torno in Romania settimana prossima, probabilmente mercoledi' - se vi fa...

posted @ giovedì 26 marzo 2009 14:40 | Feedback (377) | Filed Under [ Carillon .NET Varie Bugs? ]

Sul cast del foreach

Nel suo post di ieri, "foreach l'insidioso", Luca si e' chiesto come mai il seguente snippet: using System.Collections.Generic; interface IPersistent { } class Invoice : IPersistent { } class Order : IPersistent { } class Program {     static void Main() {         List<IPersistent> changedDocuments = new List<IPersistent>();         changedDocuments.Add(new Invoice());         changedDocuments.Add(new Order());         foreach (Invoice changedInvoice in changedDocuments) { }     } } compili. Secondo me, il comportamento del compilatore e' giusto, voluto e documentato. Le specifiche del linguaggio (15.8.4, ECMA-334), dicono: "A foreach statement of the form foreach(V v in x) embedded-statement is then expanded to: {     E e = ((C)(x)).GetEnumerator();     try {         V v;         while (e.MoveNext()) {             v = (V)(T)e.Current;             embedded-statement         }     }     finally {         … // Dispose e     } } The variable e is not visible to or accessible to the...

posted @ mercoledì 14 gennaio 2009 11:11 | Feedback (96) | Filed Under [ Carillon .NET ]

Quando C# e' piuttosto l'eccezione che la regola

Il comportamento del compilatore C#, presentato prima qui da Diego e poi nel mio post precedente, sembra singolare tra gli altri compilatori piu' conosciuti .NET. Il seguente snippet C# entra in stack overflow: using System; class Foo {     public virtual void Write(string s) {         Console.WriteLine("Foo virtual " + s);     } } class Bar : Foo {     public override void Write(string s) {         Console.WriteLine("Bar override " + s);     }     public void Write(string s, params string[] args) {         Write("Bar overload " + s);     } } class Program {     static void Main() {         Bar bar = new Bar();         bar.Write("Ciao!"); // Process is terminated due to StackOverflowException     } } mentre per gli altri linguaggi, stampa Bar override Ciao! Di seguito il codice equivalente in Visual...

posted @ lunedì 10 novembre 2008 23:46 | Feedback (225) | Filed Under [ Quiz Sharp Carillon .NET Bugs? ]

Quiz Sharp #71 [override/overload]

Questo post di Diego Martelli, fattomi notare da un amico, riesce secondo me a sorprendere un comportamento interessante di C#, ovvero il seguente snippet di codice entra in stack overflow: using System; class Foo {     public virtual void Write(string s) {         Console.WriteLine("Foo virtual " + s);     } } class Bar : Foo {     public override void Write(string s) {         Console.WriteLine("Bar override " + s);     }     public void Write(string s, params string[] args) {         Write("Bar overload " + s);     } } class Program {     static void Main() {         Bar bar = new Bar();         bar.Write("Ciao!");     } } Probabilmente molti si aspetterebbero che venisse stampato "Bar override Ciao!" a console e invece il metodo chiamato e' il Write con l'elenco variabile di parametri...

posted @ domenica 9 novembre 2008 11:14 | Feedback (311) | Filed Under [ Quiz Sharp Carillon .NET ]

IDisposable e le partial class

Oggi, parlando con il mio collega Daniel, e' uscita fuori una situazione interessante. Supponiamo che avete un tool che vi genera una classe partial che implementa IDisposable: using System; partial class Foo : IDisposable { public void Dispose() { Console.WriteLine("implicit"); } } Se volete cambiare il comportamento del Dispose senza toccare il codice generato sopra, basta implementare esplicitamente l'interfaccia IDisposable: using System; partial class Foo { void IDisposable.Dispose() { Console.WriteLine("explicit"); } } A questo punto uno using(Foo foo = new Foo()){} stampera'...

posted @ giovedì 2 ottobre 2008 03:23 | Feedback (116) | Filed Under [ Carillon .NET ]

End tag required for HTML SCRIPT element

Magari lo sanno tutti ma io ci ho perso mezz'ora per capire dove sta l'errore: <script type="text/javascript" src="foo.js"></script> e <script type="text/javascript" src="foo.js" /> non sono uguali! Su IE il tag esplicito di chiusura (la prima variante) e' obbligatorio, mentre Firefox accetta tutte e due le varianti...

posted @ lunedì 14 luglio 2008 03:23 | Feedback (49) | Filed Under [ Carillon .NET Varie ]

Best practice Path.Combine

Se vogliamo che il nostro codice giri anche su Mono, dobbiamo utilizzare: Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "aaa.bbb") al posto di: AppDomain.CurrentDomain.BaseDirectory + "aaa.bbb" perche' su Mono, BaseDirectory ritorna una stringa che non finisce in Path.DirectorySeparatorChar, mentre su CLR si'. E questo va anche in generale, quando costruiamo il path da piu' pezzi, non solo nel caso della BaseDirectory. Per esempio, chi utilizza fyiReporting RDL Project su Mono, dovrebbe modificare la riga 81 nel file Runtime/RdlEngineConfig.cs nei sorgenti del progetto e ricompilare, da: file = dir + "RdlEngineConfig.xml"; a: file = Path.Combine(dir, "RdlEngineConfig.xml"); perche' la stringa dir, per come e' stata costruita, su CLR finisce in Path.DirectorySeparatorChar, mentre su Mono no. In...

posted @ domenica 4 maggio 2008 22:44 | Feedback (95) | Filed Under [ Carillon .NET Pattern Dappertutto Bugs? ]

Un'API generico a provider per i metadata dei vari ORM

Via questo post di Frans Bouma ho scoperto sotto il namespace System.Web.DynamicData.ModelProviders dell'assembly System.Web.DynamicData.dll che arriva con l'ultima release della preview di ASP.NET Dynamic Data, un'API generico composto da 4 provider per i metadata dei vari ORM (non solo Microsoft): DataModelProvider, TableProvider, ColumnProvider ed AssociationProvider. Questo unifica in buona misura le varie API che espongono i metadata degli ORM, per esempio MetaTable, MetaDataMember, MetaAssociation nel caso di LINQ to SQL, oppure quella piu' complessa dell'Entity Framework: EntitySet, EdmMember, NavigationProperty, etc. Frans ha gia' scritto un model provider per il suo LLBLGen Pro, sarebbe bellissimo averne uno anche per NHibernate. E...

posted @ sabato 3 maggio 2008 02:53 | Feedback (104) | Filed Under [ Carillon .NET Pattern Dappertutto VSX ]

Brian Grunkemeyer sulla storia del TypeCode e dell'interfaccia IConvertible

Visto l'interesse che ha suscitato l'ultimo post, ho scritto a Brad Abrams chiedendo conferma per la mia supposizione e dettagli sulla storia dell'interfaccia IValue, lui mi risponde subito indirizzandomi a Brian Grunkemeyer e stamattina trovo nella mia casella email, scritto da Brian, questo splendido pezzo della storia di .NET: This is a good question. I was digging through the history of this file to see if I could figure out what happened, and it’s not clear. We’ve had this “hole” in the TypeCode enum since October of 2000, and I can’t find an older set of bits. But, I’m sure...

posted @ lunedì 17 marzo 2008 19:24 | Feedback (165) | Filed Under [ Un po' di storia Carillon .NET ]

Sull'enum TypeCode e sull'interfaccia fantoma IValue

Oggi Raf sul messenger mi chiede se conosco un modo piu' diretto per capire se un tipo sia primitivo oppure String o DateTime (questo per evitare degli if...). Pensandoci un po', arrivo a questa soluzione: (int)Type.GetTypeCode(type) > 2 dove type e' il tipo in causa. Lui prova e mi dice che va benissimo mentre io gia' sto pensando di bloggare questa riga di codice :-) L'enum TypeCode infatti, contiene nella sua lista di valori maggiori a 2 tutti i 12 tipi primitivi piu' il DateTime e lo String, proprio quello che voleva Raf. A questo punto gli chiedo come denominare questa categoria di...

posted @ mercoledì 12 marzo 2008 06:49 | Feedback (113) | Filed Under [ Un po' di storia Carillon .NET ]

L'OR Designer e' stato scritto con DSL Tools

Lo sapevate che l'Object Relational Designer e la parte di generazione di codice per le classi LINQ to SQL in VS2008 sono state scritte utilizzando Microsoft DSL Tools che fa parte di VS SDK? - l'ho scoperto tramite il Reflector mentre studiavo l'API di questo potentissimo framework che e' DSL Tools: tra le classi che derivano da Microsoft.VisualStudio.Modeling.ModelElement, classe fondamentale per la rappresentazione degli elementi di un domain model, si trovano anche le classi internal dell'OR Designer. Questo dovrebbe dare piu' fiduccia a chi inizia o valuta di estendere Visual Studio per un certo DSL utilizzando DSL Tools! - parti complesse del...

posted @ lunedì 21 gennaio 2008 03:29 | Feedback (225) | Filed Under [ Carillon .NET VSX ]

raise accessor in C++/CLI

Due anni e mezzo fa, parlavo in questo post, di tre eventi all'interno delle classi del framework, tutti e tre nell'assembly Microsoft.VisualBasic.dll, provvisti non solo dei classici accessor add e remove, ma anche di raise (.fire in IL), accessor che non esiste ancora in C# e finivo il post chiedendomi in quale linguaggio sia stato scritto quell'assembly, Microsoft.VisualBasic.dll. E oggi scopro che C++/CLI (ECMA-372, 19.6.2) mette a disposizione tre accessor anziche' due: add, remove e raise. Quindi, lo snippet del mio vecchio post, diventa in C++/CLI: delegate void FooFiredEvent(); ref class Foo {     FooFiredEvent^ m_FooFired;     public: event FooFiredEvent^ FooFired {         void add(FooFiredEvent^ value) {             m_FooFired += value;         }         void remove(FooFiredEvent^ value) {             m_FooFired...

posted @ lunedì 8 ottobre 2007 22:37 | Feedback (22) | Filed Under [ Carillon .NET ]

Un modo di marcare il valore di default di un enum

"Do provide a value of zero on simple enums" dice una linea guida del FDG (p. 95). Ma forse sarebbe ancora piu' espressivo marcare questo valore di default di un enum appunto come una default value expression (ECMA-334, 14.5.14) anziche' impostarlo a 0. Cioe', scrivere: public enum Compression{    None = (int)default(Compression),    GZip,    Deflate} al posto di None = 0. In ogni caso, il compilatore genera lo stesso IL. E' solo un'idea, che ne dite?

posted @ sabato 28 luglio 2007 20:12 | Feedback (29) | Filed Under [ Carillon .NET Pattern Dappertutto ]

GetCallingLanguage [la soluzione di un quiz di Claudio Brotto]

Un po' di mesi fa, Claudio Brotto, aveva proposto un simpatico quiz a cui vorrei dare adesso una soluzione (in realta' la soluzione e' per una variante leggermente modificata del quiz). Si tratta praticamente di scrivere un metodo pubblico in un assembly in tal modo che, chiamandolo da un altro assembly, questo metodo produca una stringa diversa in base al linguaggio in cui e' stato scritto l'assembly chiamante. Per esempio, questo metodo dovrebbe ritornare la stringa "C#" se chiamato da un assembly scritto in C#, oppure "Basic" se chiamato da un assembly scritto in VB.NET, etc. Piccolo vincolo della mia...

posted @ domenica 8 luglio 2007 19:04 | Feedback (8) | Filed Under [ Quiz Sharp Carillon .NET ]

Le 19 cose impossibili delle classi statiche

Per ottenere l'elenco completo delle cose che NON si possono fare con le classi statiche, e' piu' facile andare nel file "errors.h" di SSCLI 2.0 e cercare gli errori che riguardano le static class. L'elenco ottenuto e' piu' dettagliato rispetto a quello del paragrafo 17.1.1.3 delle specifiche: CS0418, AbstractSealedStatic ("una classe astratta non può essere sealed o static") CS0441, SealedStaticClass ("una classe non può essere contemporaneamente static e sealed") CS0708, InstanceMemberInStaticClass ("impossibile dichiarare membri di istanza in una classe statica") CS0709, StaticBaseClass ("una classe non può derivare da una classe statica") CS0710, ConstructorInStaticClass ("le classi statiche non possono avere costruttori di istanza") CS0711, DestructorInStaticClass ("le classi statiche...

posted @ venerdì 23 marzo 2007 14:43 | Feedback (111) | Filed Under [ Carillon .NET ]

Quiz Sharp #61 [la soluzione]

La soluzione al Quiz Sharp #61 mi sembra abbastanza interessante per meritare un post a parte (nomi come Miguel de Icaza, Jon Skeet, Abhinaba Basu, hanno considerato strano il comportamento del compilatore C# 2.0 nel comparare i valori value type a null) La risposta corretta al quiz e' che eseguendo lo snippet si ottiene un'eccezione a runtime (StackOverflowException). Vediamo di seguito il perche', con le specifiche in mano: Per evaluare l'espressione value != null nell'implementazione dell'operatore, dove value e' un not-nullable value type, il compilatore applica alcune conversioni. Per esempio, per ogni nullable type, esiste una conversione implicita dal tipo null al...

posted @ mercoledì 21 marzo 2007 18:36 | Feedback (16) | Filed Under [ Quiz Sharp Carillon .NET ]

[OT] Interfacce con costruttori di istanza in PHP 5.2.0

Via questo post di Kevin Williams, scopro che PHP, a partire dall'ultima versione (5.2.0), supporta "constructors in interfaces to force constructor signature checks in implementations". Si potrebbe quindi scrivere: <?phpinterface IFoo {    public function __construct ();}class Foo implements IFoo {    public function __construct () {        echo "Ciao!\n";    }}?> Senza il costruttore della classe Foo, avremmo ottenuto l'errore: "Class Foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (IFoo::__construct)". Come avevo gia' scritto in questo vecchio post, il CLR non consente costruttori di istanza nelle interfacce (costruttori static invece, si').

posted @ venerdì 29 dicembre 2006 22:05 | Feedback (20) | Filed Under [ Carillon .NET Varie ]

Default constructor and not nullable value type generic parameter constraints

Questo post di David Hayden, segnalato da Michele, che riprende un paragrafo da questo libro (non l'ho ancora visto nelle librerie ma un altro libro di Christian Gross mi è piaciuto molto) mi ha incuriosito perché sia in C# (CS0451) che in VB.NET (BC32103) è impossibile avere insieme una constraint struct/Structure e una constraint new()/New. E quindi mi sono chiesto come mai "without the class constraint, the compiler doesn't know if the type T is a value type or reference type and hence has to check for both"? Se struct e new() non possono stare insieme non significa che il...

posted @ lunedì 6 novembre 2006 00:01 | Feedback (25) | Filed Under [ Carillon .NET ]

EqualsDefault e l'Equals statico della System.Object

A volte, un umile metodo come l'Equals statico della classe System.Object può rendersi sorprendentemente utile. Per esempio, in una classe generica in cui il type parameter T può essere sia una class che una struct, abbiamo la necessità di controllare che un'istanza di T sia default(T). class Foo<T> { public bool EqualsDefault(T t) { /* ? */ } } Senza l'Equals statico le soluzioni sono abbastanza bruttine: non possiamo avere t == null perché T può essere una struct; non possiamo avere t == default(T) per l'errore CS0019 ("Operator '==' cannot be applied to operands of type 'T' and 'T'"); non possiamo...

posted @ domenica 29 ottobre 2006 13:24 | Feedback (3) | Filed Under [ Carillon .NET Pattern Dappertutto ]

La risposta di Paul Vick: VB.NET and C# differ in their overload resolution rules

Grazie a Corrado, ieri ho ricevuto questo commento da Paul Vick al post "Overloading non-generic virtual methods in generic classes (C# vs VB.NET)": "Corrado Cavalli pointed me to your question -- the answer is that VB and C# differ in their overload resolution rules. C# only looks at one level in the hierarchy at a time, while VB looks at all the members in the inheritance chain at the same time. So C# only sees Bar::DoSomething(T), while VB sees Bar::DoSomething(T) and Bar::DoSomething(Object). We prefer less generic methods over more generic methods, so you get the Object overload" Thank you Paul!

posted @ venerdì 27 ottobre 2006 09:12 | Feedback (31) | Filed Under [ Carillon .NET ]

[GUISA] Quando non rispettare le linee guida?

Ho appena creato un thread sul forum di GUISA (Gruppo Utenti Italiani Solution Architect) in cui offro un esempio dove ha senso che il metodo GetHashCode ritorni sempre un valore costante e dove il metodo Equals è molto atipico: due istanze sono uguali se sono istanze del tipo contenente questi metodi - quindi semantica statica per una classe non-statica. Cercherò di postare lì le cose che riguardano l'architettura, per seguire sia io che voi più facilmente i feedback, mentre qui sul blog solo una piccola info.

posted @ mercoledì 25 ottobre 2006 16:29 | Feedback (22) | Filed Under [ Carillon .NET Pattern Dappertutto GUISA ]

Overloading non-generic virtual methods in generic classes (C# vs VB.NET)

Ho  notato un comportamento diverso (C# vs VB.NET) per l'overloading di metodi virtuali non-generici in classi generiche e, come notava il buon Raffaele in una discussione sul messenger "la regola di scegliere l'una o l'altra non è dettata dal CLS e qui scoppiano i problemi quando traduci un listato - un bel pasticcio". Lo snippet C# sotto: using System; class Foo {     public virtual void DoSomething(object o) {          Console.WriteLine("void Foo::DoSomething(object)");     }} class Bar<T> : Foo {     public void DoSomething(T t) {          Console.WriteLine("void Bar<T>::DoSomething(T)");     }      public override void DoSomething(object o) {          Console.WriteLine("void Bar<T>::DoSomething(object)");     }} class Baz : Foo {     public override void DoSomething(object o) {         ...

posted @ sabato 21 ottobre 2006 13:54 | Feedback (46) | Filed Under [ Carillon .NET ]

I metodi giganti del Framework .NET (1.1 e 2.0)

In "verticale": Il metodo del Framework con il corpo più lungo (sia per la versione 1.1 che per la 2.0) è il metodo pubblico void Go() della classe internal System.Web.RegularExpressions.TagRegexRunner1 che si trova nell'assembly System.Web.RegularExpressions.dll; il suo corpo in IL ha 5770 bytes, che corrispondono a 862 righe di codice C# in Reflector! - posso dire pazzesco?... Se invece consideriamo solo i metodi pubblici dei tipi pubblici, abbiamo: per la versione 2.0, il metodo pubblico void Register() della classe pubblica System.Globalization.CultureAndRegionInfoBuilder che si trova nell'assembly sysglobl.dll; il suo corpo in IL ha 1088 bytes, che corrispondono a 69 lunghe righe di codice C#...

posted @ domenica 8 ottobre 2006 16:15 | Feedback (2) | Filed Under [ Carillon .NET Pattern Dappertutto ]

L'errore CS0310 e le classi abstract

Il messaggio dell'errore CS0310 (e anche la sua descrizione) secondo me è incompleto, cioè non basta che un tipo abbia un costruttore pubblico senza parametri per poter essere utilizzato come type parameter in un tipo generico con una constructor constraint. Il messaggio dell'errore dice: "The type 'typename' must have a public parameterless constructor in order to use it as parameter 'parameter' in the generic type or method 'generic'". Controesempio: abstract class Foo{    public Foo() { }} class Bar<T> where T : new() { } Il tipo Foo ha un costruttore pubblico senza parametri ma l'espressione new Bar<Foo>() non compila (error CS0310). La frase nelle...

posted @ venerdì 6 ottobre 2006 20:09 | Feedback (30) | Filed Under [ Carillon .NET Bugs? ]

Implementare l'evento di un'interfaccia

Qualcuno (diciamo alle prime armi con .NET) si potrebbe chiedere dove sta l'implementazione di un evento di un'interfaccia, vista la sintassi C#: interface IFoo {     event EventHandler Bar; }   class Foo : IFoo {     public event EventHandler Bar; } Sembra che la classe Foo non implementi un bel nulla, e invece, con questa sintassi, noi in realtà accettiamo l'implementazione di default dei metodi add_Bar e remove_Bar, che la scriverà per noi il compilatore (vedi il codice IL corrispondente). Meno confusione si crea quando scegliamo di definire esplicitamente l'evento nella classe Foo; lì i metodi delle funzioni di accesso add e remove tolgono ogni dubbio sull'implementazione dell'evento.

posted @ domenica 24 settembre 2006 17:34 | Feedback (22) | Filed Under [ Carillon .NET ]

Riflettete sul Reflector

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 Reflectornamespace 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 2namespace System.Data.SqlClient{    public sealed class SqlClientFactory : DbProviderFactory    {       ...

posted @ martedì 5 settembre 2006 14:15 | Feedback (31) | Filed Under [ Carillon .NET Pattern Dappertutto ]

I delegate sono struct???

Quasi da non credere (J. Duffy, "Professional .NET Framework 2.0", p. 61): "The actual IL emmited shows some of the complexities of delegates in the underlying type system:" struct MyDelegate : System.MulticastDelegate{    //[...]} "[...] Notice first that the MyDelegate type breaks one of the rules discussed above, namely that structs cannot derive from types other than ValueType. Delegates have special support in the CTS, so this is allowed." Abbastanza sconvolgente questo paragrafo, non trovate?

posted @ giovedì 3 agosto 2006 09:11 | Feedback (46) | Filed Under [ Carillon .NET ]

L'attributo EditorBrowsable per gli entrypoint pubblici

Certi linguaggi, come per esempio J#, impongono l'accesso public al metodo entrypoint. Però, dal punto di vista del utilizzatore della classe che contine l'entrypoint, questo membro public non presenta alcun interesse, cioè non viene quasi mai richiamato dal codice. Sto pensando quindi che si potrebbe decorare con l'attributo EditorBrowsable(EditorBrowsableState.Never) in tal modo da non comparire nell'elenco intellisense dei membri pubblici della classe.

posted @ giovedì 16 febbraio 2006 10:15 | Feedback (21) | Filed Under [ Carillon .NET Pattern Dappertutto ]

L'ordine degli attributi multi-use in C#, VB, J#

Ogni compilatore è libero di ordinare l'elenco di attributi multi-use che decorano un elemento di codice in base alle sue proprie regole. In questo senso, le specifiche di C# avvertono: "The order in which attributes are specified in an attribute section, and the order in which sections attached to the same program entity are arranged, is not significant" (ECMA-334, 24.2). I seguenti 3 snippet equivalenti, scritti rispettivamente in C#, VB e J#: using System; [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5), Foo(6), Foo(7), Foo(8), Foo(9), Foo(10)][AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]class FooAttribute : Attribute{    public FooAttribute(int index)    {        _index = index;    }     private int _index;    public int...

posted @ lunedì 13 febbraio 2006 16:47 | Feedback (18) | Filed Under [ Carillon .NET ]

Microsoft Common Compiler Infrastructure

Per chi vuole scriversi un compilatore per il CLR, sicuramente un grande aiuto troverà nella Microsoft Common Compiler Infrastructure (CCI). Questo framework non è direttamente scaricabile ma arriva (per esempio) insieme al compilatore Zonnon o all'utilissimo FxCop. Purtroppo, le versioni della CCI che troverete in Zonnon e FxCop sono diverse: Zonnon: System.Compiler.dll (Compiler oriented replacement for System.Reflection and System.Reflection.Emit) System.Compiler.Framework.dll (Contains a collection of standard compiler base classes as well as visitors for the standard node types defined in System.Compiler) System.Compiler.Runtime.dll (Extensions to the Common Language Runtime used by the Common Compiler Infrastructure)FxCop Microsoft.Cci.dll (Incorpora alcune classi di Fugue, senza però utilizzare gli assembly...

posted @ domenica 29 gennaio 2006 22:19 | Feedback (11) | Filed Under [ Carillon .NET ]

implicito/esplicito, visibilità/implementazione, C#/VB

Parlando con Massimo oggi, ho notato delle simmetrie/asimmetrie nelle scelte di quelli che hanno progettato C# e VB: Nel caso di VB, la visibilità implicita (cioè pubblica) dell'implementazione di un'interfaccia definisce un'implementazione implicita dell'interfaccia. Stessa parola ("implicita") ma due sensi diversi. Nel caso di C#, la visibilità esplicita dell'implementazione di un'interfaccia non è consentita per definire un'implementazione esplicita. Stessa parola ("esplicita") ma due sensi diversi anche in questo caso.

posted @ martedì 13 dicembre 2005 14:53 | Feedback (32) | Filed Under [ Carillon .NET ]

Classi nel Framework che portano lo stesso nome

Lo sapevate che esistono classi nel Framework .NET che portano lo stesso nome (ovviamente in namespace differenti)? [mscorlib]System.Runtime.Remoting.Contexts.SynchronizationAttribute - [System.EnterpriseServices]System.EnterpriseServices.SynchronizationAttribute Altri esempi? (l'esempio di sopra l'ho trovato nel recente libro di Nagel, p. 34) (Aggiornamento 20/11/2005): Nei commenti trovate l'elenco completo dei 60 esempi di classi pubbliche nella 2.0 (Beta 2) che portano lo stesso nome e che hanno come root namespace, System (altrimenti sarebbero stati molti di più).

posted @ domenica 20 novembre 2005 15:56 | Feedback (30) | Filed Under [ Carillon .NET ]

Dove metto il type parameter? [post con Massimo Prota]

Facendo oggi con Massimo il refactoring con generics della classe DotNetNuke.Common.Utilities.Null, sono nate alcune considerazioni sui tipi generici. Di seguito il post a 4 mani - si nota anche dall'italiano :-) Avendo una classe static Foo che espone funzionalità generiche e più conveniente definire il type parameter per un metodo (Dummy) piuttosto che per la classe. Questo perché a runtime verrà generata un'unica classe Foo con più metodi Dummy anziché più classi Foo con un metodo Dummy ciascuna. Per esempio, il seguente snippet:using System; class Foo<T>{      static Foo()      {            Console.WriteLine("Foo<{0}>", typeof(T));      }      public static void Dummy() { }} class Foo{      static Foo()      {           ...

posted @ lunedì 7 novembre 2005 19:36 | Feedback (25) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Entrypoint & CRT startup

Se in C# questo snippet: using System;using System.Reflection; class Foo{      static void Main()      {            Console.WriteLine(Assembly.GetEntryAssembly().EntryPoint.Name);      }} stampa Main a console, non la stessa cosa si può dire dell'equivalente C++: using namespace System;using namespace System::Reflection; void main(){    Console::WriteLine(Assembly::GetEntryAssembly()->EntryPoint->Name);} che stampa a console: main mainCRTStartup oppure _mainCRTStartup in base alle opzioni: /clr:safe /clr:pure rispettivamente /clr:oldSyntax (oppure /clr:initialAppDomain) dove mainCRTStartup e _mainCRTStartup sono funzioni di C/C++ run-time startup. Il compilatore (tranne nel caso /clr:safe) chiama prima queste funzioni per le inizializzazioni necessarie alla C/C++ run-time library (variabili globali, heap, etc) e quindi saranno loro quelle decorate con .entrypoint in IL e non il metodo main dello snippet. L'opzione /clr:safe invece, produce codice verificabile e non...

posted @ venerdì 14 ottobre 2005 14:16 | Feedback (1) | Filed Under [ Carillon .NET ]

Block statements & nop

Se avete bisogno di indviduare il corrispondente IL di un frammento di metodo, basta creare un block in C# per il rispettivo frammento di codice (che sarà delimitato da due nop in IL): <method signature in C#>{      // codice...       {       //      // zona di interesse      //      }       // codice...} <method signature in IL>{      // codice...       nop       //      // zona di interesse      //      nop       // codice...}

posted @ martedì 11 ottobre 2005 21:02 | Feedback (15) | Filed Under [ Carillon .NET ]

Le magie di XslCompiledTransform

Appena ho visto la nuova XslCompiledTransform (in 2.0) è stato colpo di fulmine. E da questo esempietto fatto al volo, solo per rendere l'idea, capirete subito perché: using System;using System.Text;using System.IO;using System.Xml;using System.Xml.Xsl; class Test{      static void Main()      {            string methodName = "Foo";            StringBuilder methodCode = new StringBuilder();             methodCode.AppendLine  ("// ritorna la stringa Ciao ragazzi!");            methodCode.AppendFormat("public string {0}()", methodName);            methodCode.AppendLine  ("{");            methodCode.AppendLine  ("   StringBuilder sb = new StringBuilder();");            methodCode.AppendLine  ("   sb.Append(\"Ciao \");");            methodCode.AppendLine  ("   sb.Append(\"ragazzi!\");");            methodCode.AppendLine  ("   return sb.ToString();");            methodCode.AppendLine  ("}");             Console.WriteLine(ExecuteMethodCode(methodCode.ToString(), methodName));      }       static string ExecuteMethodCode(string methodCode, string methodName)      {            StringBuilder xsl = new StringBuilder();            StringBuilder result = new StringBuilder();             string...

posted @ mercoledì 5 ottobre 2005 16:46 | Feedback (16) | Filed Under [ Carillon .NET ]

Grammar ambiguities in C# 2.0

Secondo voi, se questo snippet compila: class Test{      static void Foo(bool b1, bool b2)      {            System.Console.WriteLine("{0}, {1}", b1, b2);      }       static void Main()      {            bool b1 = expr1;            bool b2 = expr2;            Foo(b1, b2);      }} e lasciando identiche le espressioni expr1 e expr2, dovrebbe per forza compilare senza errori anche quest'altro snippet?: class Test{      static void Foo(bool b1, bool b2)      {            System.Console.WriteLine("{0}, {1}", b1, b2);      }       static void Main()      {           Foo(expr1, expr2);      }} Non sempre! Ed eccone un esempio, suggerito dalle specifiche (ECMA-334, 3rd Ed., 9.2.3 "Grammar ambiguities" - dove troverete anche altre situazioni!): // compila senza errori e stampa True, Falseclass Test{      static void Foo(bool...

posted @ domenica 2 ottobre 2005 20:25 | Feedback (11) | Filed Under [ Carillon .NET ]

GetILAsByteArray e l'opzione /bytes dell'ildasm

Per vedere "the actual bytes (in hex) as instruction comments" nel codice IL, abbiamo l'opzione /bytes dell'ildasm. Per esempio, per il metodo Foo::Sum della classe: class Foo{      public int Sum(int a, int b)      {            return a + b;      }} otteniamo: IL_0000:  /* 00   |                  */ nopIL_0001:  /* 03   |                  */ ldarg.1IL_0002:  /* 04   |                  */ ldarg.2IL_0003:  /* 58   |                  */ addIL_0004:  /* 0A   |                  */ stloc.0IL_0005:  /* 2B   | 00               */ br.s       IL_0007IL_0007:  /* 06   |                  */ ldloc.0IL_0008:  /* 2A   |                  */ ret dove con rosso sono scritti in esadecimale gli opcode (e i loro parametri! - vedi lo 00 nella colonna...

posted @ martedì 20 settembre 2005 16:02 | Feedback (143) | Filed Under [ Carillon .NET ]

Sul modificatore static per i membri di una static class

Mi stavo chiedendo perché dobbiamo specificare esplicitamente il modificatore static per tutti i membri di una static class. Per esempio, tutti i membri di un'interfaccia, hanno implicitamente l'accesso public ed è vietato specificare qualunque modificatore. Cerco di darmi una risposta, ma è solo una mia supposizione: Visto che possiamo dichiarare una static class così: partial class Foo{      //...} static partial class Foo{      //...} senza essere obbligati a specificare static per tutte le dichiarazioni parziali: static partial class Foo{      //...} static partial class Foo{      //...} la dichiarazione implicita static per i membri creerebbe confusione nella dichiarazione parziale: partial class Foo{      // membri static o instance?} visto che potrebbe...

posted @ martedì 20 settembre 2005 11:49 | Feedback (20) | Filed Under [ Carillon .NET ]

Sul valore di default del layout

Mi sono chiesto: perché il valore di default dell'enum System.Runtime.InteropServices.LayoutKind è LayoutKind.Sequential e non LayoutKind.Auto? (come dicono le specifiche ECMA-335, Partition II, 10.1.2, 3rd ed.).Secondo me, la risposta sarebbe questa: il layout di default è auto per i tipi di riferimento e sequential per i tipi di valore mentre l'unica signature in cui appare l'enum LayoutKind è quella del costruttore dell'attributo pseudocustom System.Runtime.InteropServices.StructLayoutAttribute che, anche se applicabile sia alle classi che alle struct, viene quasi sempre utilizzato per le struct (da dove anche il nome, StructLayoutAttribute).

posted @ mercoledì 7 settembre 2005 13:03 | Feedback (21) | Filed Under [ Carillon .NET ]

Boxed value types work identical to unboxed value types in VB .NET

Corrado segnala in questo post, lo strano uso che il compilatore VB .NET fa del metodo RuntimeHelpers.GetObjectValue. Anche una semplice assegnazione: Dim foo As Object = New Object viene vista come: object foo = System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(new object()); In realtà, non è così strano. Leggendo i commenti nel codice Rotor per il metodo GetObjectValue, si capisce un po' di più la ragione: "GetObjectValue is intended to allow value classes to be manipulated as Object but have aliasing behavior of a value class. The intent is that you would use this function just before an assignment to a variable of type Object. If the value being assigned is a...

posted @ martedì 30 agosto 2005 17:07 | Feedback (60) | Filed Under [ Carillon .NET ]

Sub New vs. Sub [New] in VB .NET

Nel caso di New in VB .NET, c'è una differenza evidente però magari poco conosciuta tra la variante escaped (sinistra, metodo) e la variante non-escaped (destra, costruttore): Class Foo     Sub [New]()     End Sub End Class Class Foo     Sub New()     End Sub End Class ...

posted @ martedì 16 agosto 2005 11:14 | Feedback (12) | Filed Under [ Carillon .NET ]

Bis-bisnipoti di System.Attribute

Non mi aspettavo di trovare proprio 4 generazioni di discendenti di System.Attribute. Un esempio? L'attributo System.Data.SqlClient.SqlClientPermissionAttribute (e i suoi fratellini).

posted @ giovedì 28 luglio 2005 12:31 | Feedback (13) | Filed Under [ Carillon .NET ]

Obsolete assemblies

Se l'attributo System.ObsoleteAttribute avesse il target anche su AttributeTargets.Assembly, si eviterebbe di decorare tutti i tipi di un assembly interamente obsoleto come Obsolete. Per esempio, nella Beta 2, tutti i tipi dell'assembly Microsoft.VisualC.dll sono decorati con [Obsolete(”Microsoft.VisualC.dll is an obsolete assembly and exists only for backwards compatibility.”)]. Potremmo cosi' avere, piu' semplice, una volta sola per l'intero assembly: [assembly:Obsolete(”Microsoft.VisualC.dll is an obsolete assembly and exists only for backwards compatibility.”)]

posted @ domenica 24 luglio 2005 20:49 | Feedback (2) | Filed Under [ Carillon .NET Bugs? ]

ConstructorNeedsTagAttribute e le interfacce con costruttore

Mi sono ricordato di questa domanda di Giancarlo: "Perchè nella definizione di una interfaccia non c'è la possibilità di specificare anche una firma per eventuali costruttori?" incontrando nel framework (Beta 2) l'attributo System.Web.UI.ConstructorNeedsTagAttribute. Praticamente, decorando con [ConstructorNeedsTag(true)] una classe, "garantiamo" al client della classe il fatto che essa abbia un costruttore con un parametro di tipo string. E' proprio vero il fatto che l'AOP permette di estendere un linguaggio con nuove costruzioni...

posted @ domenica 24 luglio 2005 19:15 | Feedback (14) | Filed Under [ Carillon .NET ]

Hurry up, Mr. Finalizer!

Sperimentando in questi giorni delle cose, mi sono fermato su una prova che mi è apparsa piuttosto strana: il seguente snippet using System; class Foo{      static int i = 0;       ~Foo()      {            Foo f = new Foo();            Console.WriteLine(++i);      }       static void Main()      {            Foo foo = new Foo();      }} stampa a console numeri consecutivi e si ferma senza errore dopo qualche decina di migliaia!... La spiegazione l'ho trovata solo adesso, dopo tante fantasie sognate, in una pagina (467) di Richter: "Quando è in corso il regolare arresto di un processo," [...] "ciascun metodo Finalize ha circa 2 secondi di tempo per essere restituito....

posted @ lunedì 18 luglio 2005 18:38 | Feedback (25) | Filed Under [ Carillon .NET ]

Quando lo stack overflow diventa sport e C# e J# concorrenti

Questo codice, assolutamente simmetrico, l'ho scritto apposta per essere compilato sia in C# che in J#, senza modifiche: // foo.txtclass Test{      static int i = 0;       // J# entry point      // vjc foo.txt      public static void main(System.String[] args)      {            i++;            System.Console.WriteLine(i);            Main(args);      }       // C# entry point      // csc foo.txt      public static void Main(System.String[] args)      {            i++;            System.Console.WriteLine(i);            main(args);      }} Eseguendo il foo.exe, arriva la sorpresa: il numero di cicli che la variante J# riesce a fare (159830), supera il numero di cicli della variante C# (159781), fino al messaggio: Process is terminated due to StackOverflowException. Incuriosito da questa strana vittoria del...

posted @ martedì 12 luglio 2005 21:13 | Feedback (8) | Filed Under [ Carillon .NET CLS ]

Bug System.ComponentModel.BindableSupport.Default?

A me, il fatto che il seguente snippet stampi: TrueTrueFalse a console, risulta stranissimo! using System;using System.ComponentModel; class Test{      static void Main()      {            BindableAttribute a = BindableAttribute.Default;            BindableAttribute s = new BindableAttribute(BindableSupport.Default);             Console.WriteLine(a.IsDefaultAttribute()); // True            Console.WriteLine(s.IsDefaultAttribute()); // True             Console.WriteLine(a.Equals(s)); // False???      }} Praticamente, l'enumeration System.ComponentModel.BindableSupport, così com'è definita nel framework: namespace System.ComponentModel{      public enum BindableSupport      {            No,            Yes,            Default // 2???      }} vede il valore dell'elemento Default come 2 e non come 0 (che è quello di No). In effetti, nella definizione della classe System.ComponentModel.BindableAttribute, che wrappa l'enumeration di sopra, abbiamo: namespace System.ComponentModel{      // ...      public sealed class BindableAttribute : Attribute      {            public static readonly BindableAttribute...

posted @ mercoledì 6 luglio 2005 11:58 | Feedback (8) | Filed Under [ Carillon .NET Bugs? ]

Decorando con enum

Come utilizzare un'enumeration come attribute? Nello snippet seguente mostro un semplice ma elegante pattern per il wrapping di un'enumeration (ho inserito le spiegazioni come commenti nel codice). Il fatto che il wrapper deriva da System.Attribute è solo per offrire una situazione concreta in cui il wrapping diventa utile e necessario. Con il valore 0 per il primo elemento dell'enumeration ho voluto ricordare una best practice spesso dimenticata: "ensure that 0 is a valid state for value types" (vedi l'item 8 del libro "Effective C#" di Bill Wagner, oppure (aggiornamento 1: 06/07/05) la regola 10.9 nel libro di Balena e Dimauro). using...

posted @ martedì 5 luglio 2005 21:46 | Feedback (7) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Best practice per gli obsolete in un enum

Succede che a volte dovete cambiare i nomi degli elementi in un'enum, per esempio, da ConsoleKey.BackSpace a ConsoleKey.Backspace, oppure da ConsoleKey.SpaceBar a ConsoleKey.Spacebar, utilizzando l'attributo Obsolete. Attenzione all'ordine degli elementi con lo stesso valore! L'elemento obsolete deve essere posizionato dopo l'elemento valido dello stesso valore. Il seguente snippet: class Test{      static void Main()      {            Foo f = (Foo)1;            System.Console.WriteLine(f);      }} stampa SomeThing a console se l'enum è: // NO!public enum Foo{      [Obsolete("Use Foo.Something.")]      SomeThing = 1,      Something = 1} e Something se l'enum è: // OK!public enum Foo{      Something = 1      [Obsolete("Use Foo.Something.")]      SomeThing = 1,}

posted @ mercoledì 29 giugno 2005 20:18 | Feedback (13) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Full Carillon .NET Archive

Powered by:
Powered By Subtext Powered By ASP.NET