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 ]

Divertimento con il Reflector e un firing method

Se il seguente snippet: delegate void FooFiredEvent(); class Foo{      public event FooFiredEvent FooFired;            public void RaiseFooFired()      {            if (FooFired != null)            {                  FooFired();            }      }} lo compiliamo: csc foo.cs poi lo disassembliamo : ildasm foo.exe /out=bar.il e nel file disassemblato, bar.il, inseriamo la riga in rosso: .event FooFiredEvent FooFired{      .addon instance void Foo::add_FooFired(class FooFiredEvent)      .removeon instance void Foo::remove_FooFired(class FooFiredEvent)      .fire instance void Foo::RaiseFooFired()} dopodiché lo riassembliamo: ilasm /exe bar.il e apriamo il file bar.exe col Reflector impostato per C#, avremo una sorpresa: nel codice disassemblato dell'evento FooFired, è apparsa una sezione, raise, che non c'è ancora nel linguaggio C# :-) public event FooFiredEvent FooFired{      [MethodImpl(MethodImplOptions.Synchronized)] add      {            this.FooFired...

posted @ lunedì 23 maggio 2005 20:47 | Feedback (16) | Filed Under [ Carillon .NET ]

Specifying C# concepts in a mathematical precise manner

Un davvero splendido corso di "Managed Computation" tenuto nella primavera dell'anno scorso al Politecnico federale di Zurigo da Prof. Robert Stärk per gli studenti iscritti al programma di MSc in Computer Science, è scaricabile da questa pagina. Nelle più di 500 slide del corso, le specifiche di C# vengono modellate come macchine astratte (ASM). Una gioia leggerlo, abbiate solo pazienza!

posted @ sabato 21 maggio 2005 19:15 | Feedback (13) | Filed Under [ Carillon .NET Varie ]

Explicitly calling event accessors

Si sa che i metodi corrispondenti agli event accessor devono seguire un pattern di denominazione (vedi CLS Rule 33 e ECMA-335, Partition I, 10.4). Per esempio, l'accessore add deve seguire il pattern: void add_<EventName> (<DelegateType> handler) Luca, in questo interessante post, è arrivato ad aver bisogno di richiamare questi event accessor. Provando col compilatore C#, si ottiene l'errore CS0571 ("cannot explicitly call operator or accessor"). Vediamo se, per il seguente snippet, il compilatore C# genera per i metodi add_FooFired e AddFooFired lo stesso codice IL: class Foo{      private FooFiredEvent mFooFired;      public event FooFiredEvent FooFired      {            add            {                  mFooFired += value;            }            remove            {                 ...

posted @ venerdì 20 maggio 2005 15:50 | Feedback (8) | Filed Under [ Carillon .NET ]

Launch for user

Non sempre quando vi appare una finestra "Just-In-Time Debugging", nel messaggio "An exception 'MyNamespace.MyException' has occurred in MyApplication.exe", l'eccezione debba essere una exception. Può capitare di incontrare al posto di 'MyNamespace.MyException', 'Launch for user' :-) Un esempio, in questo snippet: class Foo{  static void Main()  {    System.Diagnostics.Debugger.Break();  }} Secondo me, crea un po' di confusione il messaggio.

posted @ mercoledì 4 maggio 2005 15:59 | Feedback (102) | Filed Under [ Carillon .NET Bugs? ]

The following custom attribute is added automatically

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...

posted @ venerdì 22 aprile 2005 11:35 | Feedback (112) | Filed Under [ Carillon .NET ]

goto DumpTheSucker

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 ;-)

posted @ giovedì 21 aprile 2005 18:11 | Feedback (13) | Filed Under [ Carillon .NET Varie ]

Because the parent does not exist

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...

posted @ mercoledì 20 aprile 2005 12:51 | Feedback (31) | Filed Under [ Carillon .NET ]

Inside the Rotor CLI - un viaggio gratis

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".

posted @ domenica 17 aprile 2005 18:26 | Feedback (19) | Filed Under [ Carillon .NET Varie ]

if true, if false

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...

posted @ domenica 17 aprile 2005 17:47 | Feedback (13) | Filed Under [ Carillon .NET ]

Errore in SLAR sul parser SecurityElement

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).

posted @ lunedì 11 aprile 2005 09:26 | Feedback (8) | Filed Under [ Carillon .NET Bugs? ]

Piccola best practice per gli entry point

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.

posted @ martedì 5 aprile 2005 16:55 | Feedback (14) | Filed Under [ Carillon .NET Pattern Dappertutto ]

I bug degli esempi su RaiseEvent, confermati da Paul Vick

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

posted @ lunedì 4 aprile 2005 12:12 | Feedback (23) | Filed Under [ Carillon .NET Bugs? ]

LOCAL array initializer?

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...

posted @ domenica 3 aprile 2005 18:27 | Feedback (17) | Filed Under [ Carillon .NET ]

PrivateImplementationDetails e gli array initializer in C# (ovvero il Quiz Sharp #47 dietro le quinte)

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...

posted @ sabato 2 aprile 2005 16:27 | Feedback (1) | Filed Under [ Quiz Sharp Carillon .NET ]

Esempi errati nelle specifiche VB .NET

Il seguente snippet è preso dal paragrafo 9.6.2 delle specifiche VB .NET: Imports SystemClass Raiser  Public Event Constructed()  Public Sub New()    RaiseEvent Constructed()  End SubEnd ClassModule Test  Private WithEvents x As Raiser  Private Sub HandleConstructed() Handles x.Constructed    Console.WriteLine("Constructed")  End Sub  Public Sub Main()    x = New Raiser  End SubEnd Module Non mi spiego come un errore così elementare (vedi la Reference: "Non-shared events should not be raised within the constructor of the class in which they are declared. Although such events do not cause runtime errors, they may fail to be caught by associated event handlers") possa essere fatto proprio da...

posted @ giovedì 31 marzo 2005 02:42 | Feedback (18) | Filed Under [ Carillon .NET Bugs? ]

GetType(GetType)

In Visual Basic .NET, la keyword GetType è più vicina alla BCL rispetto alla keyword corrispondente typeof in C#. Questa vicinanza però, non deve creare confusione tra keyword e metodo. Mi spiego con un esempio tipo quiz :-) Supponiamo di avere questi due file in Visual Basic .NET, Foo.vb: ' Foo.vbPublic Class Foo : End Class e Test.vb: ' Test.vbImports SystemClass Test  Shared Sub Main()    Console.WriteLine(Type.GetType(GetType(Foo).FullName))  End SubEnd Class che compilano senza errori. Il risultato dell'esecuzione di Test però, dipende dalle "compiler option" con cui li abbiamo compilati: se compiliamo con: vbc test.vb foo.vboppure con:vbc /t:module foo.vbvbc /addmodule:foo.netmodule test.vbl'esecuzione di Test stampa Foo a console; se...

posted @ mercoledì 30 marzo 2005 03:04 | Feedback (8) | Filed Under [ Carillon .NET ]

toString or not ToString

Avere in un linguaggio .NET un metodo pubblico, non statico, conforme al CLS e di una classe pubblica, in un assembly, non necessariamente vuol dire che possa essere richiamato da un altro assembly! L'esempio non è evidente: il metodo toString in questo snippet J#: class A extends java.lang.Object{  public String toString()  {    return "A::toString";  }} non può essere richiamato da C#: class Test{  static void Main()  {    // error CS0117: 'A' does not contain a definition for 'toString'     System.Console.WriteLine(new A().toString());  }} se non lo sostituiamo con ToString. Da VisualBasic .NET invece, va ("identifiers are case insensitive"): Class Test  Shared Sub Main()    ' OK   ...

posted @ venerdì 18 marzo 2005 17:27 | Feedback (11) | Filed Under [ Carillon .NET CLS ]

Un altro motivo a favore delle proprietà

Quasi sempre, come motivo per preferire le proprietà pubbliche ai campi pubblici di istanza, si presenta quello della possibilità di validazione dei valori nella classe corrente o nelle classi derivate.  Ne ho trovato invece un altro, molto interessante, nel libro di Lowy (p. 378, sottolineatura mia): "Neither programmatic nor declarative security can protect against untrusted code accessing public fields because no stackcalls are involved. Never provide public fields, and always use properties".

posted @ sabato 5 marzo 2005 11:40 | Feedback (6) | Filed Under [ Carillon .NET ]

Bug System.CodeDom.Compiler.Executor?

Mi sembra contraddittorio avere per una classe sealed una security action InheritanceDemand... Succede così per la classe Executor: namespace System.CodeDom.Compiler{  [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")]  [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]  public sealed class Executor  {    //  }} La prova: PermissionSetAttribute è uno pseudo-custom attribute, perciò troviamo InheritanceDemand come flag inheritcheck nella direttiva .permissionset. Raf? :-)

posted @ venerdì 4 marzo 2005 17:07 | Feedback (6) | Filed Under [ Carillon .NET Bugs? ]

sealed solo fuori dall'assembly?

Sto pensando che sarebbe interessante un nuovo modificatore per una classe public che la rendi sealed solo fuori dal suo assembly... Cosa ne pensate?

posted @ domenica 20 febbraio 2005 21:42 | Feedback (13) | Filed Under [ Carillon .NET ]

Bug compilatore VB .NET? (StandardModuleAttribute)

Se la classe Foo la compiliamo separatamente in un file "Foo.vb": ' Foo.vb<Microsoft.VisualBasic.CompilerServices.StandardModule()> _Public NotInheritable Class Foo  Public Sub New()  End SubEnd Class con: vbc /t:library Foo.vb e proviamo a consumarla nel codice seguente: ' Test.vbClass Test  Shared Sub Main()    Dim f As Foo = New Foo  End SubEnd Class con: vbc /r:Foo.dll Test.vb otteniamo l'errore BC30371 ("Module 'Foo' cannot be used as a type.") come mostrato nel post precedente. Se invece mettiamo tutto in un file, l'errore non appare più! ' TestFoo.vb<Microsoft.VisualBasic.CompilerServices.StandardModule()> _Public NotInheritable Class Foo  Public Sub New()  End SubEnd ClassClass Test  Shared Sub Main()    Dim f As Foo = New Foo  End SubEnd Class...

posted @ domenica 13 febbraio 2005 22:45 | Feedback (44) | Filed Under [ Carillon .NET Bugs? ]

standard module & StandardModule

Nel capitolo 7.7 delle specifiche VB .NET, si può leggere: "A standard module is a type whose members are implicitly Shared and scoped to the declaration space of the standard module's containing namespace, rather than just to the standard module declaration itself. Standard modules may never be instantiated. It is an error to declare a variable of a standard module type." ed è vero: provando a istanziare uno standard module in VB .NET si ottiene l'errore BC30371 ("Module '' cannot be used as a type"). Ma come traduce il compilatore di VB .NET in IL uno standard module? Per esempio, a questo...

posted @ domenica 13 febbraio 2005 15:47 | Feedback (11) | Filed Under [ Carillon .NET ]

Dim C#

Non sapevo che in VB .NET si potesse scrivere: Dim C# dove # è il così detto type character per un double (vedi le specifiche, pp. 15-16). Mi fa impressione vedere quella riga di codice :-)

posted @ domenica 13 febbraio 2005 10:49 | Feedback (13) | Filed Under [ Carillon .NET ]

Qualcosa di nuovo sul new

Partendo da questo post di Marco Russo e indagando un po' sulla modifica di accessibilità nella sovrascrittura di un metodo virtuale in una relazione di ereditarietà, ho scoperto che, ai metodi Foo in questo codice C++: #using <mscorlib.dll> using namespace System; public __gc class A {   protected: virtual void Foo()   {     Console::WriteLine(S"A");   } }; public __gc class B: public A {   protected: virtual void Foo()   {     Console::WriteLine(S"B");   } }; public __gc class C: public B {   public: virtual void Foo()   {     Console::WriteLine(S"C");   } }; corrispondono le seguenti signature IL: .method family newslot virtual instance void Foo() cil managed // A .method family virtual instance void Foo() cil managed // B .method public virtual instance void Foo() cil managed // C dove si nota in rosso il flag...

posted @ mercoledì 9 febbraio 2005 12:53 | Feedback (52) | Filed Under [ Carillon .NET ]

VB .NET Language Specification

Grazie a questo post di Colin Coller ho scoperto, dopo quasi 2 anni dalla loro uscita, le 226 pagine di specifiche VB .NET: P. Vick, "Microsoft Visual Basic .NET Language Specification, Version 7.1", Microsoft Corporation (2003) Da una prima occhiata mi sembrano, paragonandole con quelle per C#, un po' troppo alla VB :-)

posted @ lunedì 7 febbraio 2005 10:40 | Feedback (12) | Filed Under [ Carillon .NET Varie ]

Il teorema di McEliece

Da questo post del mio connazionale Radu Grigore, scopro un bellissimo teorema di McEliece (per la cronaca, Robert McEliece è stato negli anni '60 compagno di dottorato di ricerca con Donald Knuth, vero mostro sacro dell'informatica): Any continuous strictly increasing function f : R -> R with the inverse g, g(Z) included in Z, has the dual properties: ceiling(f(x)) = ceiling(f(ceiling(x))) floor(f(x)) = floor(f(floor(x))) OK, adesso so che volete un esempio semplice in C# :-) System.Math.Sqrt è definita in {double non negativi} con valori in {double non negativi}, è monotona strettamente crescente strettamente ascendente (si dice così?) e per argomenti interi  non negativi...

posted @ lunedì 31 gennaio 2005 14:21 | Feedback (10) | Filed Under [ Carillon .NET Un po' di numeri ]

Brian Grunkemeyer è l'autore delle static class

Un pezzo di storia: nel video di questo post, dal minuto 6:13 al minuto 10:28, Brian Grunkemeyer racconta come gli è venuta l'idea delle classi statiche. E' iniziato tutto da un suo bug nella versione 1.0 del Framework: il metodo System.Environment.HasShutdownStarted non era ai tempi static, e quindi poteva essere chiamato solo tramite reflection :-) Lo racconta anche in SLAR, alla pagina 178

posted @ giovedì 27 gennaio 2005 21:09 | Feedback (11) | Filed Under [ Un po' di storia Carillon .NET ]

Compilazione di un programma vuoto in Visual C++ .NET

Alla fine sono riuscito a individuare le opzioni giuste per compilare un programma vuoto (Foo.cpp) in Visual C++ .NET: cl /CLR /LD Foo.cpp /link /NOENTRY Lo schema dei colori corrisponde a quello del post precedente. Aggiungo sotto, altri 4 commenti ai 4 precedenti: il codice IL più pulito per i programmi vuoti è generato dal compilatore Visual C# .NET (a parte, ovviamente, quello corrispondente all'IL stesso); la dimensione della DLL per Visual C++ .NET è identica a quella della DLL per JScript .NET: 3584 bytes (coincidenza, secondo me, pazzesca! - anche perché gli IL sono diversi) la direttiva .permissionset ha associata la SecurityAction RequestMinimum (System.Security.Permissions.SecurityAction.RequestMinimum)....

posted @ sabato 22 gennaio 2005 20:04 | Feedback (5) | Filed Under [ Carillon .NET ]

Leggere senza l'aiuto dell'XML il file di configurazione di un'altra applicazione

Non è detto che per leggere un file di configurazione (per esempio un web.config) di un'altra applicazione, bisogna per forza utilizzare le classi XML. Basta essere folli e scrivere una cosa come questa qui sotto, sparata oggi - e di cui ne sono contento :-) In una web application Test, che ha questo web.config: <?xml version="1.0" encoding="utf-8" ?><configuration>  <appSettings>    <add key="fooMessage" value="Hello World!" />  </appSettings></configuration> aggiungiamo questa classe: using System;using System.Configuration;using System.Collections.Specialized;namespace Ugidotnet.Configuration{  public sealed class CrossConfigSetter  {    private CrossConfigSetter(){}    public const string DataName = "AppSettings";    public static void SetAppSettingsData()    {      NameValueCollection serializableAppSettings = new NameValueCollection(ConfigurationSettings.AppSettings);      AppDomain.CurrentDomain.SetData(DataName, serializableAppSettings);    }  }} mentre nella console application da...

posted @ giovedì 13 gennaio 2005 00:17 | Feedback (11) | Filed Under [ Carillon .NET ]

extends [mscorlib]System.Object

Anche se in IL assembly una classe non eredita esplicitamente da [mscorlib]System.Object, se non specificata, questa ereditarietà è implicita anche a quel livello. Perciò: .class A{} viene trasformata dall'assembler in: .class private auto ansi A extends [mscorlib]System.Object{} Così, il fatto che System.Object sia la madre di tutti è assicurato al più basso livello possibile. Questo vuol dire che, anche se un compilatore volesse definire una classe al di fuori della gerarchia di classi che ha come root SystemObject, non potrebbe. Il testo originale delle specifiche: "If no type is specified, ilasm will add an extend clause to make the type inherit from System.Object."

posted @ venerdì 7 gennaio 2005 14:24 | Feedback (8) | Filed Under [ Carillon .NET ]

Somme in C# e VB .NET

Sapete perché il seguente codice C# non da errori a runtime mentre il corrispondente VB .NET sì (System.OverflowException)? C# VB .NET int a = int.MaxValue;int b = a + 1; Dim a As Integer = Integer.MaxValueDim b As Integer = a + 1 Semplicemente perché il compilatore C# traduce la somma nell'istruzione IL add, mentre il compilatore VB .NET la traduce nell'istruzione add.ovf (come add ma con la verifica di overflow). Più performante, ovviamente, la variante C#. Spiegazione letta nel libro di Robinson (p. 21).

posted @ venerdì 7 gennaio 2005 00:50 | Feedback (5) | Filed Under [ Carillon .NET ]

La differenza tra ILAsm e ilasm

Spesso si confondono: ILAsm = IL assembly (IL source code) ilasm(.exe) = IL assembler Questo è dovuto alla doppia rappresentazione di IL, sorgente e binaria, tra cui esiste una corrispondenza 1:1. A ogni istruzione di ILAsm corrisponde un opcode di IL che occupa 1 o al massimo 2 byte, direttamente parte dell'assembly. Quindi, quando parliamo di IL, sottintendiamo codice IL. Questa doppia rappresentazione di IL è anche il motivo per cui ilasm non è un compilatore: solo sostituisce le mnemoniche di IL con i corrispondenti opcode. Lo spiega bene Simon Robinson nel suo libro, "Expert .NET 1.1 Programming" (p. 2-3).

posted @ mercoledì 5 gennaio 2005 15:23 | Feedback (3) | Filed Under [ Carillon .NET ]

Sulla saga di JIT e StackTrace

Il problema ormai è chiuso, dopo la raffica di post di Paolo (qui, qui, qui e qui), Cristian (qui) e Raffaele (qui, qui e qui).  Con un ritardo di una settimana, non faccio adesso altro che aggiungere due ciliegine (2 cents?) sulla torta: Richter nel suo libro (pp. 443-444) avvertiva: "Ogni qualvolta si ottiene un'analisi dello stack, è possibile rilevare che alcuni metodi dello stack di chiamate non sono visualizzati nell'analisi dello stack. Il motivo di questa assenza è rappresentato dal fatto che il compilatore JIT può eseguire l'inlining dei metodi per evitare l'overhead generato dalla chiamata e dalla restituzione di un metodo...

posted @ domenica 19 dicembre 2004 20:23 | Feedback (128) | Filed Under [ Carillon .NET Bugs? ]

Sul DebuggableAttribute, le opzioni del compilatore e l'errore CS0647

Richter nel suo libro (p. 444) dice: "Il compilatore JIT (Just-In-Time) esamina l'attributo personalizzato System.Diagnostics.DebuggableAttribute applicato all'assembly. In genere, il compilatore applica questo attributo automaticamente. Se nell'attributo è specificato true per il parametro isJITOptimizerDisabled del costruttore DebuggableAttribute, il compilatore JIT non eseguirà l'inlining dei metodi dell'assembly. Per impostare questo parametro su true è possibile utilizzare l'opzione /debug del compilatore C#." E' un po' strano secondo me il fatto che isJITOptimizerDisabled sia collegato all'opzione /debug (che sta nella categoria Debugging/Error Checking e ha il significato di Emit Debugging Information) e non all'opzione /optimize (della categoria Optimizations e che ha il significato Enable/Disable Optimizations)....

posted @ domenica 19 dicembre 2004 19:03 | Feedback (6) | Filed Under [ Carillon .NET ]

Consumare da C# codice Delphi non-CLS

Abbiamo visto nel post precedente come il compilatore Delphi crea una classe finta per ogni unit così che anche il codice procedurale soddisfi la regola CLS 36. Cosa succede invece quando non gli lasciamo più spazio agli trucchi e trasgrediamo in modo esplicito una regola CLS, per esempio la CLS Rule 11 (quella sulla signature)? Potremmo da C# "consumare" un codice come quello di seguito? (al tipo Word di Delphi corrisponde in C# il tipo ushort, non CLS) // DelphiCls.paslibrary DelphiCls;usesFoo in 'Foo.pas';// inutile: Delphi non è CLS-compliant[assembly: CLSCompliant(True)]beginend. // Foo.pasunit Foo;interface// non ha una signature conforme al CLSfunction BadArgType(i: Word): Word;implementationfunction...

posted @ martedì 30 novembre 2004 01:27 | Feedback (13) | Filed Under [ Carillon .NET CLS ]

Using Delphi for .NET in C#

Esiste una regola CLS (CLS Rule 36) che dice: "Global static fields and methods are not CLS-compliant". Visto questo, vi aspettate che il seguente codice in Delphi for .NET sia CLS-compliant? Senza una classe, senza niente... :-) // Delphi for .NETlibrary Foo;uses  SysUtils;procedure DoSomething(msg: String);begin  Console.WriteLine(msg)end;beginend. Ebbene, sì! Il compilatore di Delphi for .NET, appunto per la conformità al CLS, trasforma la "procedura" DoSomething in un metodo static di una classe Foo sotto il namespace (se lo inventa lui) Foo.Units. E possiamo benissimo utilizzare la "procedura" DoSomething in C#: // C#class Test{  static void Main()  {    Foo.Units.Foo.DoSomething("Ciao");    System.Console.Read();  }} Ecco perché la mia sessione di giovedì si chiama "CLS:...

posted @ lunedì 29 novembre 2004 17:15 | Feedback (8) | Filed Under [ Carillon .NET ]

Compiler error message != error message reference

Ho notato delle piccole differenze tra alcuni messaggi d'errore generati dal compilatore C# e la documentazione di questi errori: CS3006: "Overloaded method 'method' differing only in ref or out, or in array rank, is not CLS-compliant" CS3012: "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking" In arancione ho evidenziato i pezzi mancanti nella documentazione.

posted @ lunedì 29 novembre 2004 14:02 | Feedback (10) | Filed Under [ Carillon .NET ]

Gli errori C# relativi esplicitamente al CLS

Nel file "errors.h" che contiene la lista di tutti gli errori e warning del compilatore C# del Rotor c'è scritto che "Range 3000-3999 is reserved for CLS errors". Qui sotto nella tabella, ho mappato gli errori C# riguardanti esplicitamente il CLS alle regole del CLS trasgredite: Visual C# Compiler Error / Warning Number Rotor Error Name Summary Description CLS Rule Number CLS Rule ? ERR_CLS_NoVarArgs ? ? ? ? CS3001 ERR_CLS_BadArgType Argument type 'type' is not CLS-compliant A public, protected, or protected internal method must accept a parameter whose type is compliant with the CLS. 11 All types appearing in a signature shall be CLS-compliant. (p. 49 del PDF) CS3002 ERR_CLS_BadReturnType Return type of 'method' is not CLS-compliant A public, protected, or...

posted @ lunedì 29 novembre 2004 01:19 | Feedback (94) | Filed Under [ Carillon .NET CLS ]

L'underscore e la CLS Rule 4

Mi ha attirato l'attenzione un commento di Massimo Prota a questo post di Pierre. Beh, riguarda CLS, di cui vi parlerò giovedì - a sala vuota mi sa... :-) Massimo segnalava in sostanza il fatto che in un assembly conforme al CLS non possiamo nominare gli identificatori dei campi protected con il prefisso "_" in una classe public. Ne approfitto per aggiungere delle cose magari meno conosciute: Beccare tra le 41 regole del CLS quella responsabile di questo vincolo non è immediato. Dovreste leggervi l'appendice 7 "Programming Language Identifiers" dell'"Unicode Technical Report #15" (come specificato dalla CLS Rule 4 - p. 44 del...

posted @ domenica 28 novembre 2004 17:23 | Feedback (4) | Filed Under [ Carillon .NET CLS ]

Slot per variabili locali in IL

Per ridurre la signatura delle variabili locali, IL permette di specificarle in degli slot indicizzati: [0], [1], etc. così da poter condividere uno slot con più variabili locali dello stesso tipo. Per esempio, a questo metodo Main: static void Main(){  int i = 1;} corrisponde questo codice IL in seguito a una compilazione con /debug+ .method private hidebysig static void Main() cil managed{  .entrypoint  .maxstack 1  .locals init ([0] int32 i)  ldc.i4.1  stloc.0  ret} in cui si nota lo slot [0] per la variabile i. Però, se si compila con /debug-, lo slot sparisce: .method private hidebysig static void Main() cil managed{  .entrypoint  .maxstack 1  .locals init (int32 V_0)  ldc.i4.1  stloc.0  ret} Strano, mi aspettavo a un comportamento...

posted @ domenica 7 novembre 2004 14:46 | Feedback (4) | Filed Under [ Carillon .NET ]

Compilazione di programmi vuoti in vari linguaggi .NET

Un mese fa avevo scritto due post (questo e questo) su programmi vuoti in C#. Oggi vorrei completare il quadro anche per altri linguaggi .NET, con il tabellone qui sotto che spero parli un po' da sé. Non sono riuscito a individuare le opzioni giuste per il compilatore Visual C++ (cl.exe) (con i vostri commenti magari riuscirò a completare la tabella anche per C++ e, perché no, per altri linguaggi .NET). Quattro commenti soltanto:  in Visual C# .NET non c'è bisogno di referenziare assembly che supportino la compilazione e la generazione di codice (come "Microsoft.VisualBasic.dll", "vjscor.dll", "Microsoft.JScript.dll"); Visual Basic .NET referenzia...

posted @ sabato 6 novembre 2004 17:57 | Feedback (20) | Filed Under [ Carillon .NET ]

Un warning fino in fondo: "The variable 'variable' is assigned but its value is never used"

Supponiamo che vi troviate davanti a un quiz come questo: class Foo{  static void Main()  {    string s1 = string.Empty;    string s2 = "";    double d = System.Math.PI;  }} Secondo voi, quanti warning "The variable 'variable' is assigned but its value is never used" otterreste in compilazione? Qualcuno dirà 3, un altro 2, un altro ancora 1, mentre i più fighi diranno nessuno. La risposta però è 2. Per capire il motivo non mi sono stati d'aiuto né le specifiche, nè Richter, né Box, né Gunnerson. La risposta l'ho trovata spulciando nel Rotor, nel corpo dei metodi FUNCBREC::reportUnreferencedVars (le righe 668-683) e FUNCBREC::bindAssignment (le righe 7488-7533). Vediamo cosa...

posted @ domenica 24 ottobre 2004 19:07 | Feedback (14) | Filed Under [ Quiz Sharp Carillon .NET ]

NULLSYM - the null type

Partendo dalla misteriosa frase: "The type of a null-literal is the null type" che si trova nelle specifiche, ho scritto finora quattro altri post: ("The null type?", "The null type (un po' più chiaro)",  "The null type (la risposta di Dominic Cooney)", "Di nuovo sul nulla :-)"). Oggi però, finalmente ho trovato nei sorgenti di Rotor la definizione di questo tipo: /** NULLSYM - represents the null type -- the type of the "null constant".*/class NULLSYM: public TYPESYM{}; e andando in su nella gerarchia dei simboli ho trovato: SYM the base symbol PARENTSYM (deriva da SYM) a symbol that can contain other symbols as children TYPESYM (deriva da PARENTSYM) a...

posted @ domenica 24 ottobre 2004 14:45 | Feedback (1) | Filed Under [ Carillon .NET ]

Dal Recordset al DataSet

Per trasformare un DataSet in un Recordset hanno parlato nei loro libri Dino Esposito (vedi "Programmare XML in Microsoft .NET", pp. 170-179 e pp. 326-332) e Paolo Pialorsi con Marco Russo (vedi ".NET XML & WebServices Full Contact", pp. 27-35). Magari pochi sanno la strada contraria: quella dal Recordset al DataSet. Per loro il seguente snippet: public sealed class AdoConvert {   private AdoConvert(){}   public static DataSet ToDataSet(ADODB.Recordset rs)   {     OleDbDataAdapter da = new OleDbDataAdapter();     DataTable dt = new DataTable();     DataSet ds = new DataSet();     da.Fill(dt, rs);     ds.Tables.Add(dt);     return ds;   }   public static DataSet ToDataSet(string recordsetXml)   {     ADODB.Recordset rs = new ADODB.Recordset();     ADODB.Stream stream =...

posted @ sabato 16 ottobre 2004 19:46 | Feedback (11) | Filed Under [ Carillon .NET ]

I tipi predefiniti devono essere definiti

Non poche cose si imparano provando a compilare programmi vuoti :-) Vediamone alcune: Per esempio, vi dicevo nell'altro post che: type foo.cs > foo.cscsc /t:library foo.cs produce un assembly (DLL) di 3072 bytes identico a quello prodotto se foo.cs fosse fatto solo da namespace vuoti perché il concetto di namespace è al livello del linguaggio e non scende al livello IL. Quindi se i namespace non si "applicano" a nessun tipo il compilatore giustamente li ignora. Il codice IL di questo assembly è: .assembly extern mscorlib{.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ).ver 1:0:5000:0}.assembly foo{// --- The following custom attribute...

posted @ mercoledì 6 ottobre 2004 20:45 | Feedback (52) | Filed Under [ Carillon .NET ]

No support in the CLI for the namespace concept

Vi sieti mai chiesti se i programmi vuoti (cioè da 0 bytes) compilano? Queste due righe nel VS .NET Command Prompt: type foo.cs > foo.cscsc /t:library foo.cs producono un DLL da 3072 bytes.  Forse per qualcuno sapere questo potrebbe sembrare una cosa di poco peso. Voglio però farvi notare che, se al posto del file vuoto compilate uno snippet che contiene un namespace vuoto: namespace empty{} risulterà un DLL della stessa dimensione di 3072 bytes. Se provate con ildasm a vedere il codice IL nei due casi, vedrete che sono identici.  Cosa vuol dire questo? Ci dobbiamo semplicemente ricordare che il concetto di namespace è al...

posted @ martedì 5 ottobre 2004 00:44 | Feedback (9) | Filed Under [ Carillon .NET ]

The language spec does not need to be in agreement with the type system

Michi, in questo post del 6 settembre intitolato "Reflection in disagreement with language spec" su MSDN Product Feedback Center, nota lo stesso comportamento segnalato più volte da me qui, qui e qui (e poi anche da Corrado, qui e qui) Ecco la risposta di Chris (Microsoft), due giorni dopo: "In general, the language spec does not need to be in agreement with the Type system. Many languages have different type systems which they then map to the CLR type system. The CLR type system is defined in the ECMA specs -- specifically ECMA Partition II specification -- not any specific language spec. While...

posted @ mercoledì 22 settembre 2004 16:23 | Feedback (7) | Filed Under [ Carillon .NET ]

Ghost Types

Secondo il buon senso questo metodo dovrebbe ritornare sempre false. Invece ho notato con stupore che per alcuni type full name, ritorna true! static bool IsGhostType(string typeFullName){  Type type = Type.GetType(typeFullName);  if(type != null)  {    return !type.FullName.Equals(typeFullName);  }  return false;} So che volete degli esempi :-) Eccone alcuni: System.Object[*****] (è un System.Object[*]) System.Object[*,*,*,*,*] (è un System.Object[,,,,]) System.Object[*,,*,,*] (è un System.Object[,,,,]) La canzone del giorno: Nada - "Io l'ho fatto per amore" :-)

posted @ mercoledì 22 settembre 2004 12:32 | Feedback (6) | Filed Under [ Carillon .NET ]

Accesso indicizzato agli elementi di un array unidimensionale non-vettore

In questo post affermavo (in riferimento agli array unidimensionali non-vettori, cioè di limite inferiore diverso da zero) che: "non è possibile accedere in modo indicizzato agli elementi dell'array (si devono utilizzare i metodi SetValue e GetValue)." Lo si può fare invece tramite un ArrayList: int lb = 100; // limite inferioreint ub = 1000; // limite superiore// int[] a = new int[lb..ub];Array a = Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb});ArrayList al = ArrayList.Adapter(a);al[111] = 1;Console.WriteLine("al[{0}] = {1}", 111, al[111]);

posted @ martedì 21 settembre 2004 11:15 | Feedback (22) | Filed Under [ Carillon .NET ]

System.Int32[*] via reflection

Ho indagato un po' via reflection sul tipo ritornato da System.Type.GetType("System.Int32[*]"). Ha due costruttori, tutti e due instance: il primo costruttore ha un parametro int con significato di lunghezza dell'array (in questo caso il limite inferiore sarà zero!) mentre il secondo costruttore ha due parametri int: il primo parametro rappresenta il limite inferiore mentre il secondo parametro rappresenta la lunghezza meno il limite inferiore. Sono riuscito quindi a costruire un array unidimensionale non-vettore (cioè di limite inferiore diverso da zero) utilizzando System.Activator.CreateInstance (al posto di System.Array.CreateInstance). Il codice relativo nei prossimi giorni, adesso ho un po' di fretta di andare a letto...

posted @ lunedì 20 settembre 2004 01:38 | Feedback (7) | Filed Under [ Carillon .NET ]

Ma posso creare un array unidimensionale con il limite inferiore diverso da zero? (le mie conclusioni)

L'unico modo che ho trovato possibile per utilizzare gli array unidimensionali di limite inferiore diverso da zero è questo che risulta dal seguente snippet: int lb = 100; // limite inferioreint ub = 1000; // limite superiore// int[] a = new int[lb..ub];Array a = Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb});// a[111] = 1;a.SetValue(1, 111);Console.WriteLine("a[{0}] = {1}", 111, a.GetValue(111)); Si può verificare che: il tipo di a è System.Int32[*] (ancora non ho capito bene il significato dell'asterisco che appare solo nel caso di un array unidimensionale creato con System.Array.CreateInstance e con il limite inferiore diverso da zero); gli array unidimensionali col limite...

posted @ domenica 19 settembre 2004 17:30 | Feedback (18) | Filed Under [ Carillon .NET ]

Ma posso creare un array unidimensionale con il limite inferiore diverso da zero?

Posso creare array MULTIdimensionali con un limite inferiore diverso da zero; lo spiega Richter nel suo libro alla pagina 318 e poi con un copia e incolla dello stesso esempio in SLAR alla pagina 49. Ma se voglio "estrapolare" lo stesso metodo per un array UNIdimensionale in una sintassi immaginaria: int[] a = new int[lb..ub]; // questa sintassi non è ancora implementata! dove lb è lower bound (per esempio 100) e ub è upper bound (per esempio 1000), scrivere: int[] a;// dichiarare e inizializzare lb e ub...a = (int[])Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb}); dà a run-time l'errore System.InvalidCastException ("Specified cast is...

posted @ sabato 18 settembre 2004 22:18 | Feedback (26) | Filed Under [ Carillon .NET ]

mailserver.di.unipi.it

In questo elenco sul mail server del Dipartimento di Informatica dell'Università di Pisa, troverete una serie di mailing list, alcune dedicate a .NET e di un livello che il nome di Pisa vi garantisce sempre.

posted @ sabato 18 settembre 2004 16:54 | Feedback (6) | Filed Under [ Carillon .NET ]

L'indice di un array non può mai essere int.MaxValue

Si sa che possiamo creare array con lower bound non zero, quindi è possibile avere un elemento a[..., i, ...] con i > a.Length. Mi sono chiesto allora quale sia il valore massimo che GetLowerBound e GetUpperBound possono restituire. Mi aspettavo che fosse int.MaxValue, invece per un lower bound int.MaxValue e un length 1 per una certa dimensione otteniamo System.ArgumentOutOfRangeException con il messaggio "Higher indices will exceed Int32.MaxValue because of large lower bound and/or length". Per fare il pignolo, nel nostro caso non abbiamo alcun "higher index" (la lunghezza è 1). Come mai l'errore? Non si tratta di un test ma...

posted @ sabato 18 settembre 2004 16:09 | Feedback (13) | Filed Under [ Carillon .NET ]

App.config e NUnit

Se nel vostro assembly di test (NUnit) avete un file "App.config", dovete copiare questa riga esattamente così com'è, senza sostituire nulla: copy "$(ProjectDir)app.config" "$(TargetDir)$(TargetFileName).config" e incollarla in: Common Properties > Build Events > General > Post-build Event Command Line sotto le proprietà del vostro progetto di test. Utilissimissimo tip se implementate per esempio il pattern Provider (come sto facendo io). Qualcuno conosce un'altra soluzione?

posted @ venerdì 17 settembre 2004 16:28 | Feedback (7) | Filed Under [ Carillon .NET Pattern Dappertutto ]

08 in C# e Java

In C#, "integer literals have two possible forms: decimal and hexadecimal" (9.4.4.2) ma in Java "an integer literal may be expressed in decimal, hexadecimal, or octal" (3.10.1).  Per questo, 08 in C# è 8, mentre in Java si ottiene errore di compilazione "integer number too large" (il prefisso del literal di un intero in base 8 in Java è 0). Post da ragazzini, lo so, però l'ho postato per distanziarmi da Corrado solo di 99 post... :-)

posted @ martedì 14 settembre 2004 14:19 | Feedback (10) | Filed Under [ Carillon .NET ]

Introduction to MSIL (Kenny Kerr)

Un'eccellente introduzione a MSIL scritta da Kenny Kerr in una serie di post. Per stimolarvi l'appetito, qualche spunto: "Unlike C#, CLI does not have any requirement that a method must belong to a class." "It is also possible to omit the variable names. In that case you would refer to the variables by their zero-based index in the declaration." "You must declare a constructor for a concrete reference type. Unlike languages like C# and C++, the IL assembler will not generate a constructor for you automatically." "The CLI does not recognize namespaces as a distinct concept. Rather the full type name is always used." "If...

posted @ lunedì 13 settembre 2004 13:05 | Feedback (15) | Filed Under [ Carillon .NET ]

Interfacce con costruttore static

Ieri Giancarlo mi ha chiesto via mail: "Ho sempre avuto un dubbio... Perchè nella definizione di una interfaccia non c'è la possibilità di specificare anche una firma per eventuali costruttori?" Gli rispondo qui per togliere eventualmente anche ad altri lo stesso dubbio. Partiamo da Richter, p. 326 (come si deve): "Il linguaggio CLR consente alle interfacce di contenere costruttori static.CLR non consente alle interfacce di contenere alcun costruttore di istanza." e da questo banale snippet "Foo.cs": interface IFoo{void NonUnCostruttore();} Lo compiliamo: csc /t:library Foo.cs per ottenere il codice IL: ildasm Foo.dll /out=Foo.il Il metodo NonUnCostruttore avrà questa dichiarazione in IL: .method public hidebysig newslot abstract virtual instance void NonUnCostruttore() cil managed Con l'aiuto...

posted @ sabato 11 settembre 2004 12:15 | Feedback (9) | Filed Under [ Carillon .NET ]

Interfaces don't inherit from anything

Ieri sera, dopo il post di Corrado, ho continuato a giocare un po' con le interfacce perché è venuto anche a me il dubbio di un possibile bug di IsSubclassOf... E lo snippet sotto lo dimostra: using System;using System.Reflection;interface IFoo{}public class Foo{  static void Main()  {    BindingFlags all = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;    Type ifooType = typeof(IFoo);    Type objectType = typeof(object);    Console.WriteLine("{0} is{1} subclass of {2}", ifooType.Name, ifooType.IsSubclassOf(objectType) ? "" : "'nt", objectType.Name);    Console.WriteLine("{0}\t#members = {1}", ifooType.Name, ifooType.GetMembers(all).Length);    Console.WriteLine("{0}\t#members = {1}", objectType.Name, objectType.GetMembers(all).Length);    Console.Read();  }} L'output è questo: IFoo is subclass of ObjectIFoo #members = 0Object #members = 14 Però, se IFoo fosse veramente "subclass" di Object, avremmo dovuto...

posted @ venerdì 10 settembre 2004 12:50 | Feedback (3) | Filed Under [ Carillon .NET ]

-AltroTest- (la mia soluzione)

I numeri possibili nel Quiz Sharp #36 sono: 1 - Pow(10, -2043) e 0 = 0 * Pow(10, Pow(10, 2043) - 1) Per avere un'idea sulla grandezza del numero moltiplicato con 0, pensate che un googolplex è "solo" Pow(10, Pow(10, 100)). Se al posto di 0 mettete 1, cioè 1e99...9, ovviamente il compilatore vi dà "Floating-point constant is outside the range of type 'double'". Come mai allora per 0e99...9 va tutto bene e il compilatore fornisce il risultato corretto? Il compilatore riconosce una moltiplicazione con 0 e chiude per il resto gli occhi. Quando tokenizza la parte exponent dell'espressione 0e99...9, non gli interessa di rappresentare...

posted @ martedì 7 settembre 2004 00:36 | Feedback (8) | Filed Under [ Quiz Sharp Test Sharp Carillon .NET ]

Di nuovo sul nulla :-)

Vi ricordate i miei punti di domanda sul null type? (qui, qui e qui) Per forzare il compilatore a dire di più, ho scritto una follia del genere:bool b = null.Equals(null, null) e il compilatore ha risposto coll'errore CS0023: "Operator '.' cannot be applied to operand of type '<null>'". Non trovate niente di strano? "of type '<null>'" e non "of type 'null'"! Cosa dobbiamo capire? Che il nome del null type è "<null>"?

posted @ giovedì 2 settembre 2004 13:19 | Feedback (8) | Filed Under [ Carillon .NET ]

Sub+Namespace

Tutti sanno del nesting separator (il segno "+") nel fully qualified name di una classe (in italiano come si dice? nome completo?). Ma non tutti sanno che il segno "+" può comparire anche all'interno del nome di un namespace. Non in C#, però in IL sì. Giochiamo un po': // Foo.csnamespaceA.BC {   class D{} } Compiliamo il codice C# con: csc /target:library Foo.cs otteniamo il codice IL: ildasm Foo.dll /out=Foo.il e in tutte e due le sezioni "CLASS STRUCTURE DECLARATION" e "CLASS MEMBERS DECLARATION" la dichiarazione del namespace la cambiamo da: .namespace A.BC a: .namespace 'A.B+C' e poi compiliamo il codice IL con: ilasm /DLL Foo.il Sorpresi del messaggio "Operation completed successfully"? Adesso il nome completo della classe...

posted @ mercoledì 1 settembre 2004 22:51 | Feedback (3) | Filed Under [ Carillon .NET ]

Main non è mai Obsolete

Il seguente snippet compila: using System;class Foo{  [Obsolete("", true)]  static void Main()  {    Console.WriteLine("Hello Obsolete World!");    Console.Read();  }} Ciò vuol dire che l'entrypoint Main non può mai essere Obsolete. Questo sicuramente ha senso, però mi aspettavo di vedere un warning oppure una nota a riguardo nelle specifiche.

posted @ lunedì 23 agosto 2004 14:32 | Feedback (10) | Filed Under [ Carillon .NET ]

string.Empty non è una "constant expression"!

A tutti string.Empty potrebbe sembrare un'espressione costante, ma in senso C# non lo è! Empty è definito come campo static readonly e non come const, perciò non è una "constant expression" (C# Language Specification, 14.15). Una conseguenza di questo fatto? Il seguente banalissimo snippet non compila! using System;class FooAttribute: Attribute{  public FooAttribute(string arg){}}class Test{  [Foo(string.Empty)]  static void DoSomething()  {    Console.WriteLine("I did something");  }  static void Main()  {    DoSomething();    Console.Read();  }} Otteniamo errore di compilazione: "An attribute argument must be a constant expression, typeof expression or array creation expression" e dobbiamo sostituire string.Empty con "" oppure con null. Strano, vero?

posted @ lunedì 23 agosto 2004 13:33 | Feedback (13) | Filed Under [ Carillon .NET ]

SafeDataReader e "Lettura dei dati e DbNull"

Un paragrafo (p. 72) dal libro "Expert One-on-One Visual Basic .NET Business Objects" di Rockford Lhotka (MVP, Regional Director e Software Legend - cosa gli manca?) che viene a completare quello che è stato detto in questo post "Lettura dei dati e DbNull" del nostro M.rkino (MVP anche lui): "Most of the time, we don't care about the difference between a null value and an empty value (such as an empty string or a zero), but databases often do. When we're retrieving data from a database, we need to handle the occurence of unexpected null values with code such as this: If...

posted @ giovedì 19 agosto 2004 13:11 | Feedback (21) | Filed Under [ Carillon .NET ]

Clipboard Ring per le presentazioni

Non mi vergogno di dire che ho scoperto solo stasera il "Clipboard Ring". Vi ricordate come Jay Roxe al "Whidbey Reloaded" del 8 luglio trascinava dal Toolbar pezzi di codice nella sua presentazione? A mio parere è comodissimo per gli speaker - si potrebbe sperimentare al prossimo workshop.

posted @ giovedì 19 agosto 2004 00:29 | Feedback (8) | Filed Under [ Carillon .NET ]

Il debugging? IL debugging!

Una soluzione bellissima per fare single-stepping a livello IL, postata sulla ADVANCED-DOTNET mailing list di DevelopMentor da Serge Lidin (l'autore dell'"Inside Microsoft .NET IL Assembler") Supponiamo di voler fare il debugging a livello IL di un programma Foo.cs. Dovremo procedere nel seguente modo (ho scelto una modalità da linea di comando per capire meglio i passi): 1. Visual C# .NET Compiler (Emit debugging information)csc Foo.cs /debug+ 2. .NET Framework IL Disassembler (Show original source lines as comments, Compile to file with specified name)ildasm Foo.exe /source /out=Foo.il 3. .NET Framework IL Assembler (Include debug information)ilasm Foo.il /debug 4. Development Environment (Open the specified executable to be...

posted @ venerdì 13 agosto 2004 20:30 | Feedback (7) | Filed Under [ Carillon .NET ]

Richter sì, Box no :-)

Abbiamo visto ieri, grazie all'osservazione di Nicu, che le specifiche avrebbero dovuto dire: "Any of the static members declared by the class are referenced" al posto di: "Any of the static members of the class are referenced". Curioso, sono ricorso al libro di Richter e ho scoperto che lui fa la precisazione (p. 188) che manca nelle specifiche: quando parla di campo statico, aggiunge "non ereditato"! A Box invece, manca (p. 62) questa precisazione.

posted @ mercoledì 11 agosto 2004 18:34 | Feedback (9) | Filed Under [ Carillon .NET Bugs? ]

Specifiche non troppo specifiche... :-)

Ieri per tutto il giorno vi ho parlato dell'articolo di Nicu G. Fruja in cui porta alla luce "a few gaps and mistakes in the C# reference manual, inconsistencies with different implementations of C#". Gli ho scritto chiedendogli dei commenti su "The reference of the static field B.x triggers only the initialization of A" e oggi mi ha risposto così (traduco dal rumeno): Le specifiche affermano erroneamente che: (17.11) "The execution of a static constructor is triggered by the first of the following events to occur within an application domain: An instance of the class is created. Any of the static members...

posted @ martedì 10 agosto 2004 18:51 | Feedback (9) | Filed Under [ Carillon .NET Bugs? ]

The reference of the static field B.x triggers only the initialization of A (la spiegazione)

"it is useful to think of static members as belonging to classes" (C# Language Specification, 17.2.5). Nel nostro caso (B.x), la classe è A. Si può vedere anche dal codice IL: ldsfld int32 A::x E' quindi naturale che si chiami il costruttore statico della classe A e non quello della classe B...

posted @ martedì 10 agosto 2004 13:08 | Feedback (9) | Filed Under [ Carillon .NET ]

The reference of the static field B.x triggers only the initialization of A (Nicu G. Fruja)

Avrei potuto proporlo come quiz, ma poi mi sono chiesto: "Perché essere sadici?" :-) using System;class A{  public static int x;  static A()  {   Console.WriteLine("Initializing A");  }}class B: A{  static B()  {   Console.WriteLine("Initializing B");  }}class Test{  static void Main()  {   Console.WriteLine("B.x = {0}", B.x);  }} Veramente non riesco a spiegarmi il fatto che questo snippet stampi: Initializing AB.x = 0 Perché A??? Magari chiedo a Nicu e poi ve lo dico, se mi risponde :-) Se qualcuno trova una spiegazione, varebbe la pena di postarla!

posted @ lunedì 9 agosto 2004 18:23 | Feedback (9) | Filed Under [ Carillon .NET ]

static constructor of struct (Nicu G. Fruja)

Se ci fosse stato class al post di struct, questo snippet: using System;struct P{  static P()  {    Console.WriteLine("Initializing P");  }}class Test{  static void Main()  {    P p = new P();  }} avrebbe stampato a console "Initializing P". Così invece, non stampa nulla! Dobbiamo quindi fare attenzione alla parola class in questo frammento di C# Language Specification (17.11): "The execution of a static constructor is triggered by the first of the following events to occur within an application domain: An instance of the class is created. Any of the static members of the class are referenced." "The creation of the struct instance p using the parameterless default instance constructor P() does not trigger the...

posted @ lunedì 9 agosto 2004 17:35 | Feedback (2) | Filed Under [ Carillon .NET ]

[,][] e [][,] (Nicu G. Fruja)

Questo snippet che può sembrare banale: using System;class Test{  static void Main()  {    int[,][] a = new int[2,3][];    Console.WriteLine(a.GetType());    Console.Read();  }} stampa a console System.Int32[][,] - magari qualcuno di noi si aspettava System.Int32[,][] :-)

posted @ lunedì 9 agosto 2004 17:20 | Feedback (21) | Filed Under [ Carillon .NET ]

Decorando con .entrypoint - #2

Giocando con la decorazione con .entrypoint, ho fatto dei piccoli esperimenti. In sostanza, in questi esperimenti, ho spostato la direttiva .entrypoint dal metodo Main al metodo MyMain, come vedrete negli esempi seguenti. Tutti i metodi MyMain li ho volutamente scelti con la signatura "sbagliata". Le signature corrette sono (secondo la "C# Language Specification", 10.1): static void Main() static void Main(string[] args) static int Main() static int Main(string[] args) Sono partito da questa: class Foo{  public static string MyMain()  {    return "Hello World";  }  static void Main()  {  }} Dopo il classico giro csc->ildasm->ilasm e poi esecuzione, ho incontrato in tutti gli esempi questo errore a runtime: System.MethodAccessException ma con differenti informazioni aggiuntive...

posted @ sabato 7 agosto 2004 23:57 | Feedback (13) | Filed Under [ Carillon .NET ]

Decorando con .entrypoint

Sabato scorso, Stefano ha richiamato sul suo blog il mio post "Main non public?" in cui mi chiedevo "qual è la ragione per cui un metodo Main possa avere qualunque accessibilità...". E' passata una settimana e nessuno ha risposto. Provo allora io a dare una risposta. Mi sono creato un file Foo.cs: class Foo{  static void Main()  {  }} Con: csc Foo.cs ho ottenuto l'eseguibile Foo.exe. L'ho passato poi a ildasm: ildasm Foo.exe /out=Foo.il per ottenere il codice IL: .assembly extern mscorlib{  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )  .ver 1:0:5000:0}.assembly Foo{  .hash algorithm 0x00008004  .ver 0:0:0:0}.module Foo.exe.imagebase 0x00400000.subsystem 0x00000003.file alignment 512.corflags 0x00000001.class private auto ansi beforefieldinit Foo extends [mscorlib]System.Object{}.class private...

posted @ sabato 7 agosto 2004 18:34 | Feedback (18) | Filed Under [ Carillon .NET ]

The class X already contains a definition for Y

Appena premuto il bottone "Inserici" per il post precedente, scopro un altro quiz (sempre della Session TS-2575 di 2004 JavaOne Conference presentata da Joshua Bloch e Neal Gafter) irriproducibile in C#: "5. Shades of Gray" (per essere precisi, l'autore in realtà è Dominik Gruntz e il quiz appare per la prima volta un anno e mezzo fa su Journal of Object Technology in un articolo interessante, intitolato "C# and Java: The Smart Distinctions"). Si tratta di un'altra "feature" di Java: "Java makes a distinction between the namespace of fields, methods and nested classes within a class, i.e., it is possible to...

posted @ lunedì 2 agosto 2004 19:01 | Feedback (1872) | Filed Under [ Quiz Sharp Carillon .NET ]

Member names cannot be the same as their enclosing type

Mi sono scaricato i 151 MB di PDF della "2004 JavaOne Conference" e ne stavo facendo un giro veloce quando ho trovato... che cosa? ...una session fatta solo di quiz :-) J. Bloch, N. Gafter, "Still More Programming Puzzlers", Session TS-2575, 2004 JavaOne Conference Il bello è che uno di questi quiz "4. More of the Same", è irriproducibile in C#! :-) Come mai? Perchè il quiz in questione sfrutta una "feature" di Java secondo la quale "It is possible for a method to have the same name as a constructor" ma, consigliano gli autori, "Don't ever do it". C# è nato...

posted @ lunedì 2 agosto 2004 17:38 | Feedback (58) | Filed Under [ Quiz Sharp Carillon .NET ]

The null type (la risposta di Dominic Cooney)

In un post del 10/06 "The null type" e in un altro del 14/06 "The null type (un po' più chiaro)", mi chiedevo cosa vuol dire "the null type" nella frase "The type of a null-literal is the null type". Ecco la risposta di Dominic Cooney (bravi anche i suoi fratelli! :-) Joseph e Patrick) "Re: Adrian Florea's comments on the 'null' type, As I understand it, the 'null' type doesn't exist outside verification. So, for example, if you're doing verification and a control flow path that does ldnull merges with one that does ldstr, the verification algorithm merges the null type...

posted @ sabato 31 luglio 2004 17:24 | Feedback (12) | Filed Under [ Carillon .NET ]

Main non public?

Mi sto chiedendo qual è la ragione per cui un metodo Main possa avere qualunque accessibilità... Quale sarebbe secondo voi il significato di un metodo Main non public? In Java, a partire dalla versione 1.4 è obbligatorio dichiararlo public. C# Language Specification, 2nd edition Java Language Specification, 2nd edition 10.1"Specifically, the execution environment can access the application’s entry point regardless of its declared accessibility and regardless of the declared accessibility of its enclosing type declarations." 12.1.4"The method main must be declared public, static, and void. It must accept a single argument that is an array of strings"

posted @ venerdì 30 luglio 2004 17:31 | Feedback (122) | Filed Under [ Carillon .NET ]

L'influenza di System.FlagsAttribute su ToString

Incuriosito da questo frammento dal libro di Box & Sells (l'edizione italiana, p. 119): "L'attributo [System.Flags] influenza anche l'implementazione di ToString in modo che la rappresentazione in stringa del valore sarà una lista separata da virgole dei nomi dei membri anziché del singolo membro.", ho giocato un po'. Per esempio, questo snippet: using System;class Foo{  [Flags]  enum NaN  {    Non = 1,    un = 2,    numero = 4,    reale = 8  }  static void Main()  {    NaN f = NaN.Non | NaN.un | NaN.numero | NaN.reale;    Console.WriteLine(double.NaN.ToString(new System.Globalization.CultureInfo("it-IT")));    Console.WriteLine(f.ToString().Replace(",", string.Empty));    Console.Read();  }} stampa a video: Non un numero realeNon un numero reale Un esempio meno folle :-) lo trovate nella documentazione di System.FlagsAttribute.Continuando a giocare, sono partito da questo snippet: using System;class...

posted @ giovedì 29 luglio 2004 01:59 | Feedback (14) | Filed Under [ Quiz Sharp Carillon .NET ]

Do return an empty array instead of a null reference

Questi giorni, oltre al progetto .NET su cui normalmente lavoro, dedico parte del tempo a preparare un corso di JSP e Servlet che terrò da settembre a dicembre. Sono ormai quasi 2 anni e mezzo da quando ho lasciato Java e sono scappato con .NET in un'inaspettata e dolcissima avventura :-) Guardo quindi Java con altri occhi, adesso che devo rivedere la materia. Per esempio, il metodo getParameterValues dell'interfaccia javax.servlet.ServletRequest ritorna java.lang.String[] : public java.lang.String[] getParameterValues(java.lang.String name) "Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist." Già il fatto di ritornare...

posted @ giovedì 22 luglio 2004 13:09 | Feedback (5) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Unable to start debugging on the web server - allora cambiate ASP.NET version

Pensavo che tutti avessero già scoperto la soluzione, ma dopo aver visto che Paschal Leloup (non sono tanti i blogger .NET con quasi 1500 post...) ha dovuto cancellare completamente il .NET 2.0 appena installato, mi sono detto che forse vale la pena di postarla :-) Quindi, è molto semplice: se dopo aver installato .NET 2.0 Beta 1, non vi va più niente nei "vecchi" progetti .NET 1.1 e ottenete: "Error while trying to run project: Unable to start debugging on the web server.Click Help for more information." allora andate subito in Internet Services Manager, click destro su Properties per il vostro local web site,...

posted @ mercoledì 30 giugno 2004 18:16 | Feedback (74) | Filed Under [ Carillon .NET ]

Void & System.Void - finalmente, errore :-)

Un po' di giorni fa segnalavo il fatto strano che questo codice: class Foo{  static void Main()  {    System.Console.WriteLine(System.Void.Equals(null, null));    System.Console.Read();  }} compilava (con Visual C# .NET Compiler version 7.10.3052.4) senza errori. Stasera ho scaricato e installato il ".NET Framework Version 2.0 Redistributable Package Beta 1 (x86)" uscito oggi e compilando (con Visual C# .NET Compiler version 8.00.40607.16) lo stesso codice di sopra ho ottenuto, finalmente, l'errore che aspettavo: error CS0673: System.Void cannot be used from C# -- use typeof(void) to get the void type object. Adesso sono più contento :-)

posted @ mercoledì 30 giugno 2004 00:49 | Feedback (29) | Filed Under [ Carillon .NET Bugs? ]

Sì, le interfacce derivano da System.Object :-)

Adesso è più chiaro. Questo codice: using System;interface IFoo{}class Foo{  static void Main()  {    Type i = typeof(IFoo);    Type o = typeof(object);    Console.WriteLine("{0} {1} da {2}", i.Name, i.IsSubclassOf(o) ? "deriva" : "non deriva", o.Name);    Console.Read();  }} scrive "IFoo deriva da Object" a console. Si può dire che le interfacce derivano in tutti gli effetti da System.Object. Per chi non è ancora convinto, provi a vedere che il seguente codice compila: using System;interface IFoo{}class Foo{  static void Main()  {    Console.WriteLine(IFoo.Equals(null, null));    Console.Read();  }} e scrive True a console.

posted @ lunedì 28 giugno 2004 17:18 | Feedback (22) | Filed Under [ Carillon .NET ]

Proprietà read-only e setter

La proprietà Length di System.IO.Stream e di tutte le sue classi derivate non è l'unica proprietà read-only per cui esiste nella stessa classe un metodo setter ma lo sono anche le proprietà In, Out ed Error della classe System.Console: public sealed class Console{  //...  private static TextReader _in;  public static TextReader In  {    get    {      //...    }  }  public static void SetIn(TextReader newIn)  {    //...  }  private static TextReader _out;  public static TextReader Out  {    get    {      //...    }  }  public static void SetOut(TextWriter newOut)  {    //...  }  private static TextWriter _error;  public static TextReader Error  {    get    {      //...    }  }  public static void SetError(TextWriter newError)  {    //...  }  //...} Ho verificato via reflection che questi sono gli unici casi all'interno del Framework di proprietà read-only pubbliche con setter pubblico nella stessa classe pubblica. Secondo me è interessante questa...

posted @ lunedì 28 giugno 2004 11:32 | Feedback (14) | Filed Under [ Carillon .NET Pattern Dappertutto ]

System.IO.Stream.Length

public abstract class Stream: MarshalByRefObject, IDisposable{  //...  public abstract long Length {get;}  public abstract void SetLength(long value);  //...} Proprietà read-only e setter come metodo...Secondo voi è stata una scelta oppure uno strano errore progettuale? Lo so, prima o poi scriverò una mail a Brad... :-)

posted @ lunedì 28 giugno 2004 01:13 | Feedback (8) | Filed Under [ Carillon .NET Pattern Dappertutto ]

System.Object come tipo base di un tipo interfaccia?

Alla pagina 129 (p. 145 del file PDF) dello "Standard ECMA-334, C# Language Specification, 2nd edition", ho incontrato una frase curiosa: "If T is an interface-type, the base types of T are the base interfaces of T and the class type object" (le sottolineature in tutte le citazioni sono mie) Un tipo interfaccia ha come tipo base anche System.Object? In che modo dobbiamo interpretare questa affermazione? Solo il fatto che "le interfacce sono sempre considerate come tipi di riferimento"? (Richter, p. 330) Come possiamo verificare via reflection il fatto che un'interfaccia ha come tipo base la System.Object? Sempre Richter dice, alla pagina...

posted @ domenica 27 giugno 2004 16:17 | Feedback (8) | Filed Under [ Carillon .NET ]

Void & System.Void

Possono anche sembrarvi uguali i seguenti due snippet: // Snippet 1using System;class Foo{  static void Main()  {    Console.WriteLine(Void.Equals(null, null));    Console.Read();  }} // Snippet 2class Foo{  static void Main()  {    System.Console.WriteLine(System.Void.Equals(null, null));    System.Console.Read();  }} ma non lo sono per niente! :-) Mentre il primo dà l'errore che tutti si aspettano: System.Void cannot be used from C# -- use typeof(void) to get the void type object. il secondo scrive senza problemi un bel True a console! :-) Dovrei pensare un po' al perché...

posted @ lunedì 21 giugno 2004 00:30 | Feedback (13) | Filed Under [ Carillon .NET Bugs? ]

The null type (un po' più chiaro)

In riferimento alla mia perplessità sul null type, ho trovato alcuni spunti in questo documento: C++/CLI Language Specification. Candidate Base Document: p. 43"The null type is a special type that exists solely to support the null literal, nullptr (also referred to as the null value constant). No instances of this type can be created; the only way to obtain a value of this type is via the nullptr literal, whose type is the null type." p. 37"The null literal (nullptr) is not an lvalue." p. 61"The sizeof operator shall not be applied to an expression that has null type." L'equivalente di nullptr in C#...

posted @ lunedì 14 giugno 2004 02:23 | Feedback (11) | Filed Under [ Carillon .NET ]

String ==-ity in Java e C# (cosa dicono gli standard)

In riferimento al mio post precedente, vediamo cosa dicono gli standard: Java Language Specification, 2nd edition Standard ECMA-334. C# Language Specification, 2nd edition 15.21.3While == may be used to compare references of type String, such an equality test determines whether or not the two operands refer to the same String object. The result is false if the operands are distinct String objects, even if they contain the same sequence of characters. The contents of two strings s and t can be tested for equality by the method invocation s.equals(t).3.10.5Strings computed at run time are newly created and therefore distinct. 14.9.7 (p. 167)Two...

posted @ domenica 13 giugno 2004 19:28 | Feedback (11) | Filed Under [ Carillon .NET ]

0 non è maggiore di -0

Se vi chiedete perché 0 > -0 è False, la risposta è semplicissima: 0 == -0E se vi chiedete ancora perché 0 == -0, la risposta è nuovamente semplicissima :-)Il risultato dell'operatore: int operator -(int x); si ottiene sottraendo x da 0. Nel nostro caso: -0 = 0 - 0 = 0 quindi 0 == -0

posted @ domenica 13 giugno 2004 16:12 | Feedback (9) | Filed Under [ Carillon .NET ]

String ==-ity in Java e C#

L'articolo "(Not So) Stupid Questions: String Equality" su java.net, è nato dalle perplessità di Vladimir V. Ostromensky inviate alla redazione del sito, riguardanti il risultato "strano" del seguente codice Java: Compile the following: // StringTester.javapublic class StringTester{  public static void main(String args[])   {    String aString = "myValue";    String bString = "myValue";    String cString = "";    if(args.length ==1 ) cString = args[0];    boolean test1 = aString.equals(bString);    System.out.println("a.equals(b): " + aString + ".equals("+bString+") is " + test1);    boolean test2 = aString == bString;    System.out.println("a==b: " + aString + " == " + bString+" is " + test2);    boolean test3 = aString.equals(cString);    System.out.println("a.equals(c): " + aString + ".equals("+cString+") is " + test3);    boolean test4 = aString...

posted @ sabato 12 giugno 2004 17:26 | Feedback (7) | Filed Under [ Carillon .NET ]

Array Initializer :-)

Via Alex Papadimoulis, un modo più "simpatico" per inizializzare un array di n + 1 stringhe a string.Empty: int n = 99;string[] arr = string.Empty.PadRight(n, ',').Split(','); Ho modificato un po' il codice, il post originale si trova qui.

posted @ sabato 12 giugno 2004 01:24 | Feedback (2) | Filed Under [ Carillon .NET Varie ]

The null type?

Una frase un po' misteriosa alla pagina 61 in basso nello standard ECMA-334 (C# Language Specification): The type of a null-literal is the null type. Voi cosa ci capite? Cosa vuol dire "the null type"?

posted @ giovedì 10 giugno 2004 17:55 | Feedback (6) | Filed Under [ Carillon .NET ]

Opposites are not contradictory but complementary :-)

Questo pezzo di codice, anche se è troppo scolastico, lo so..., magari permetterà ad alcuni di capire meglio perché MinValue = MaxValue + 1 e cosa vuol dire complemento binario: using System;class Foo{  static void Main()  {    Console.WriteLine("MinValue in binario {0}", Convert.ToString(int.MinValue, 2).PadLeft(32, '0'));    Console.WriteLine("MaxValue in binario {0}", Convert.ToString(int.MaxValue, 2).PadLeft(32, '0'));    Console.WriteLine("MinValue {0} il complemento binario di MaxValue", int.MinValue == ~int.MaxValue ? "è" : "non è");    Console.Read();  }}

posted @ martedì 1 giugno 2004 14:35 | Feedback (14) | Filed Under [ Carillon .NET ]

Così gli ultimi saranno i primi :-)

Responsabile per il loop infinito notato qui da M.rkino: for(int i = int.MinValue; i <= int.MaxValue; i++){  Console.Write(".");} è questa "identità": MaxValue + 1 = MinValue cioè, all'ultimo i++ il valore della i da MaxValue ridiventa MinValue.

posted @ martedì 1 giugno 2004 01:44 | Feedback (5) | Filed Under [ Quiz Sharp Carillon .NET ]

più O meno? più E meno! :-)

I campi MaxValue e MinValue forniti dal tipo System.Int32 sono due costanti, definite rispettivamente 0x7fffffff (0 seguito da 31 1) e 0x80000000 (1 seguito da 31 0), cioè l'uno è il complemento binario dell'altro. public struct Int32 //...{ public const int MaxValue = 0x7fffffff; public const int MinValue = unchecked((int)0x80000000); //...} L'operatore unchecked si deve al fatto che la costante hexadecimale 0x80000000 è del tipo uint (Pow(2, 31)) e il cast ad un int produce overflow (Pow(2, 31) > MaxValue). Questi valori spiegano l'osservazione di M.rkino che Int32.MinValue = -Int32.MinValue.Vediamo qui di seguito come:Abbiamo:MinValue = -Pow(2, 31)MaxValue = Pow(2,...

posted @ martedì 1 giugno 2004 01:08 | Feedback (8) | Filed Under [ Carillon .NET ]

Undebugable

In un programma "vuoto": 1 class Foo2 {3   static void Main()4   {5   }6 } la sessione di debug inizia, nel caso di questo codice, direttamente con la riga 5 ("the next statement that will be executed").Poi, si sa che per il codice dopo un:for(;;);si ottiene un warning "Unreachable code detected", appunto perché il compilatore scopre il fatto che quella porzione di codice non sarà mai eseguita. Ciò vuol dire che, per il seguente codice: 1 class Foo2 {3   static void Main()4   {5     for(;;);6   }7 } non esiste alcuna riga su cui il debugger si possa fermare! :-)

posted @ venerdì 28 maggio 2004 01:33 | Feedback (3) | Filed Under [ Carillon .NET ]

System.Double.Epsilon - il valore esatto

Sul valore di System.Double.Epsilon, la documentazione dice solo che "The value of this constant is 4.94065645841247e-324". Vediamo se, utilizzando la tabella della rappresentazione su 64 bit di un double, riusciamo a trovare il valore esatto di questa costante.Se 0<E<2047 allora -1023<E-1023<1024. Siamo quindi nel caso:Pow(-1,S)*Pow(2,-1022)*(0.F)Ma siccome Epsilon>0 abbiamo S=0 e:Epsilon = Pow(2,-1022)*(0.F)F è il numero minino, positivo e minore di 1, che si rappresenta in modo binario su 52 bit, quindi:F = Pow(2,-52)e Epsilon = Pow(2,-1022)*Pow(2,-52)cioè Epsilon = Pow(2,-1074). Valore confermato da SLAR dove, alla pagina 157, si può leggere: "A System.Double can represent [...] the finite set of non-zero values...

posted @ lunedì 24 maggio 2004 00:30 | Feedback (6) | Filed Under [ Carillon .NET ]

Double Inside

Da uno scambio di messaggi questi giorni sul Messenger con M.rkino e Gianluca, sono usciti fuori alcuni aspetti della System.Double, a prima vista strani. Per esempio, questo di seguito, presentato da Brian Grunkemeyer in SLAR (p. 156): "You might wonder why this simple code would throw an OverflowException: string s = Double.MaxValue.ToString();double d = Convert.ToDouble(s); The Convert.ToDouble() method throws an exception due to rounding errors. Note that the IEEE spec for doubles says that a double has about 15.7 decimal digits worth of precision, but to accurately represent that number you need to print out 17 digits to avoid rounding errors." Lo standard a...

posted @ giovedì 20 maggio 2004 23:58 | Feedback (2) | Filed Under [ Carillon .NET ]

Curiosità Math.Ematiche :-)

Console.WriteLine(Int16.MaxValue == (int)(4 * Double.Epsilon * Double.MaxValue * Int64.MaxValue));Console.WriteLine(Int16.MaxValue == 4 * (int)(Double.Epsilon * Double.MaxValue * Int64.MaxValue));

posted @ giovedì 20 maggio 2004 18:23 | Feedback (11) | Filed Under [ Carillon .NET ]

struct? System.Enum nel tooltip intellisense di VS .NET

Anche il tooltip intellisense di Visual Studio "vede" erroneamente System.Enum come una struct (perché utlizza reflection): "struct System.EnumProvides the base class for enumerations."

posted @ martedì 18 maggio 2004 14:38 | Feedback (12) | Filed Under [ Carillon .NET ]

typeof(System.Enum).IsXXX is more that likely a bug

"typeof(System.Enum).IsXXX does behave strangely, and is more that likely a bug. We'll take a look at that soon, and hopefully have a fix if it's deemed a problem"leggo nel commento di Joel Pobar (PM SSCLI) su questo post recente di Brad Abrams. Adesso vado a fare la nanna, ho perso tutta la sera con le stranezze di typeof(System.Enum).IsXXX

posted @ lunedì 17 maggio 2004 02:50 | Feedback (10) | Filed Under [ Carillon .NET Bugs? ]

a class = not a value type or interface?

Nella documentazione della proprietà IsClass della classe System.Type, c'è scritto:"Gets a value indicating whether the Type is a class; that is, not a value type or interface"E' vero che gli insiemi {ValueType}, {Interface} e {Class} sono disgiunti però esiste un tipo t che non fa parte né dal {ValueType}, né dall'{Interface}, né dal {Class}, cioè l'espressione !t.IsClass && !t.IsValueType && !t.IsInterface è true. Questo tipo è System.Enum di cui ho parlato in un altro post, sempre oggi. Vediamo come si potrebbe correggere la definizione. Innanzitutto, cos'è un tipo?"type declarations: class types, interface types, array types, value types, and enumeration types"In...

posted @ domenica 16 maggio 2004 23:39 | Feedback (7) | Filed Under [ Carillon .NET ]

L'unica classe che non è classe!

Una conseguenza interessante del fatto che "System.Enum is the only reference type that extends System.ValueType" (Brad Abrams, SLAR, p. 174) è quella che typeof(System.Enum).IsClass ritorna false! E' quindi l'unico tipo t all'interno del Framework per il quale l'espressione t.IsAbstract && !t.IsClass && !t.IsInterface è true!Tutto ciò si spiega guardando l'ultima parte del codice (quella sottolineata) della proprietà IsClass:public bool IsClass {  get   {    return ((GetAttributeFlagsImpl() & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class && !IsSubclassOf(Type.valueType));  }}dove valueType è:private static readonly Type valueType = typeof(System.ValueType); La conclusione? La conclusione è che esiste una classe che non è classe :-) Meno male che è soltanto una. :-)

posted @ domenica 16 maggio 2004 18:25 | Feedback (9) | Filed Under [ Carillon .NET ]

IsSubclassOf

A riguardo del mio post "Non esistono delegate singlecast", la verifica che un tipo t sia delegate o no scopro che si poteva fare in modo più semplice richiamando IsSubclassOf: t.IsSubclassOf(typeof(System.MulticastDelegate))

posted @ domenica 16 maggio 2004 01:33 | Feedback (10) | Filed Under [ Carillon .NET ]

BaseMethod vs. base.Method

Sto guardando la classe System.Collections.Specialized.NameObjectCollectionBase e le sue classi derivate e non capisco la ragione del prefisso "Base" di alcuni suoi metodi protected (BaseAdd, BaseClear, BaseGet, BaseGetAllKeys, BaseGetAllValues, BaseGetKey, BaseHasKeys, BaseRemove, BaseRemoveAt, BaseSet). Questi metodi sono richiamati dai loro metodi corrispondenti (Add, Clear, Get, GetAllKeys, GetAllValues, GetKey, HasKeys, Remove, RemoveAt, Set) nelle classi derivate ma, secondo me, queste richiamate andavano fatte come base.Method() anziché BaseMethod() e i metodi di forma BaseMethod nella classe base rinominati Method. In più, NameObjectCollectionBase sembra l'unica classe che abbia questo pattern strano.Un po' di refactoring o qualcosa mi sfugge?

posted @ sabato 15 maggio 2004 01:42 | Feedback (7) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Interfacce "Provider"

Ho trovato all'interno del Framework tre interfacce di questa forma:public interface IServiceNameProvider{  ServiceResultType GetServiceName(ServiceParameterType param);}una specie di Strategy. Service Name Interface Method Service Result Service Parameter Format System.IFormatProvider GetFormat System.Object System.Type Service System.IServiceProvider GetService System.Object System.Type HashCode System.Collections.IHashCodeProvider GetHashCode System.Int32 System.Object

posted @ domenica 9 maggio 2004 18:13 | Feedback (6) | Filed Under [ Carillon .NET Pattern Dappertutto ]

NotSupportedException - quasi come se fosse una feature di linguaggio

Esiste una classe (System.NotSupportedException ma ce ne sono anche altre) che ha un ruolo più profondo nella progettazione in generale di una gerarchia di classi, quasi come se fosse una feature di linguaggio:"There are methods that are not supported in the base class, with the expectation that these methods will be implemented in the derived classes instead. The derived class might implement only a subset of the methods from the base class, and throw NotSupportedException for the unsupported methods." (.NET Framework Class Library Reference)"A typical scenario is when a base class declares a method that derived classes are required to...

posted @ sabato 1 maggio 2004 18:20 | Feedback (14) | Filed Under [ Carillon .NET Pattern Dappertutto ]

KB818803 patch download

Per chi non vuole chiamare MS PSS per risolvere KB 818803 in .NET 1.1. le patch si possono scaricare da InstantASP  per Windows 2000 e per Windows 2003 Server

posted @ venerdì 30 aprile 2004 11:35 | Feedback (11) | Filed Under [ Carillon .NET ]

Workaround per Infragistics.WebUI.UltraWebNavigator.UltraWebMenu

Per chi lavora con Infragistics NetAdvantage 2004 Volume 1 e vuole utilizzare Infragistics.WebUI.UltraWebNavigator.UltraWebMenu non solo in maniera drag-and-drop del componente, un workaround per evitare System.NullReferenceException è questo: sostituire la riga:   string appDir = Page.Request.ServerVariables["APPL_PHYSICAL_PATH"];nel metodo:   public int ReadXmlFile(string, bool, bool)della classe:   Infragistics.WebUI.UltraWebNavigator.UltraWebMenu ("UltraMenu.cs")con:   string appDir = System.Web.HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"];

posted @ sabato 24 aprile 2004 17:04 | Feedback (43) | Filed Under [ Carillon .NET Bugs? ]

ECMA TR/84

Joel Marcey, che firma la prefazione del libro di Brad Abrams, è anche l'autore di questo piccolo e simpatico tool di cui racconta nella prefazione, scritto in C# (un'unica classe, Intel.DSL.ECMA.DocGen) per trasformare le specifiche CLI da XML a Word. Adesso si chiama, un po' pomposo :-), ECMA TR/84 e lo trovate qui (20,2 MB), sorgenti compresi (31,1 KB) :-)

posted @ venerdì 23 aprile 2004 23:43 | Feedback (10) | Filed Under [ Carillon .NET ]

Dottore in dotcctor :-)

Per essere ancora più dottori in dotcctor (.cctor è l'abbreviazione di costruttore di classe), a parte la lettura del post di Brad Abrams segnalato oggi da Corrado e degli articoli di Jon Skeet e Satya Komatineni, otterrete un'immagine completa su questo argomento leggendo 4 pagine (pp. 187-190) nel libro di Richter e 3 (pp. 60-62) nel libro di Box e Sells. E se dopo ne avete ancora voglia e desiderate andare veramente fino in fondo, leggete per ultimo questo post del micidiale Chris Brumme. Molto interessante una delle proposte di Jon Skeet alla fine del suo articolo:"An attribute would be a perfectly reasonable solution...

posted @ domenica 18 aprile 2004 17:55 | Feedback (16) | Filed Under [ Carillon .NET ]

/win32res via IDE

In VJ# è possibile tramite VS passare /win32res al compilatore. In VC#, proprio no...

posted @ giovedì 8 aprile 2004 00:57 | Feedback (3) | Filed Under [ Carillon .NET ]

Utilizzare file di risorse unmanaged in applicazioni managed

Per chi, come me, deve utilizzare file di risorse unmanaged (Win32) in applicazioni .NET, questo articolo di Kenny Kerr, "Icon Browser: An Exercise in Resource Management" sarà di grande aiuto.Nel mio progetto, un porting di un prodotto client/server scritto in VB6 in un'applicazione web scritta in ASP.NET e C#, devo utilizzare le icone di un file .RES (non è proprio banale)

posted @ mercoledì 7 aprile 2004 14:11 | Feedback (9) | Filed Under [ Carillon .NET ]

Non esistono delegate singlecast

Per vedere se un tipo t è delegate o no, basta verificare se deriva da System.MulticastDelegate: t.BaseType != null && t.BaseType.Equals(typeof(System.MulticastDelegate)) cioè non è necessaria la verifica singlecast (System.Delegate). La storia strana che spiega tutto ciò la potete leggere nel libro di Richter (pp. 375-376 per la traduzione italiana) e nel post di Brad Abrams.

posted @ domenica 4 aprile 2004 20:14 | Feedback (9) | Filed Under [ Carillon .NET ]

C(very)#

Pierre segnala qua un benchmark di C# per calcoli scientifici. Io ne ho trovato un altro, sempre recente. Mi è rimasto un debole per queste cose visti i quattro anni ('92-'96) spesi pensando a robe CFD e a tanta matematica... Per chi ha la curiosità di leggere le conclusioni dell'inchiesta sul citato fallimento di ARIANE5

posted @ martedì 16 marzo 2004 02:08 | Feedback (14) | Filed Under [ Carillon .NET ]

new è troppo new

Io non sarei così radicale come Ian Griffiths nel suo commento sul post di Dino: "If you ever use new at all, you should aim to remove it at the earliest opportunity. It's not something you would ever choose to design in". Basta fare una ricerca nei sorgenti di Rotor per incontrare più volte public new per esempio e non penso che gli sviluppatori del framework non abbiano trovato la "earliest opportunity" per togliere via new :-) Il campo System.IO.StreamWriter.Null per esempio "nasconde" il campo System.IO.TextWriter.Null da cui deriva e a prima vista non vedo come si poteva scrivere senza new...

posted @ mercoledì 10 marzo 2004 18:03 | Feedback (12) | Filed Under [ Carillon .NET Pattern Dappertutto ]

new/Shadows

Chi altro poteva rispondere meglio alla domanda di Dino se non appunto il papà di C# Anders Hejlsberg nella sua eccellente conversazione con Bill Venners su versioning (cioè new), virtual and override? E gli argomenti mi sembrano molto "real-world", come chiedeva Dino

posted @ mercoledì 10 marzo 2004 12:40 | Feedback (4) | Filed Under [ Carillon .NET ]

Prima ISerializable aveva SetObjectData

Scopro direttamente dalla bocca di Peter de Jong, il papà della serializzazione .NET (cioè dalle sue slide presentate al secondo Rotor Workshop come "History, Architecture, and Implementation of the CLR Serialization and Formatter classes") che: Constructor is not in Interface, so compiler can’t check whether it presentConstructor isn’t inherited, so each subclass needs its own constructorEarlier  version used SetObjectData instead of constructor e più avanti nella conferenza: ISerializable underwent many changes E' quello che notavo in un mio post anteriore sull'asimmetria dell'ISerializable - quindi nelle prime versioni c'era anche SetObjectData! Sicuramente motivi di performance hanno determinato il disegno attuale. Per chi vuole vedere il...

posted @ martedì 9 marzo 2004 11:16 | Feedback (12) | Filed Under [ Carillon .NET Pattern Dappertutto ]

L'asimmetria dell'ISerializable

L'interfaccia ISerializable presenta un'asimmetria su cui secondo me varrebbe la pena di riflettere in modo più profondo: il suo metodo GetObjectData offre al formattatore un container (SerializationInfo) con tutti i dati necessari per la serializzazione e un altro (StreamingContext) con tutti i, chiamiamoli, metadati. Al contrario, per la deserializzazione, non si trova un simmetrico SetObjectData (come qualcuno si potrebbe aspettare insieme a Christoph Schittko) ma un costruttore protected per la classe che implementa l'interfaccia, costruttore che deve avere gli stessi parametri con il metodo GetObjectData - l'esistenza di questo però non la costringe nessuno... Un processo così simmetrico come quello della serializzazione/deserializzazione,...

posted @ venerdì 5 marzo 2004 01:39 | Feedback (13) | Filed Under [ Carillon .NET Pattern Dappertutto ]

Powered by:
Powered By Subtext Powered By ASP.NET