maggio 2004 Blog Posts
using System;class Foo{ static void Main() { int j = 0; for(int i = int.MinValue; i < int.MaxValue; i++) { if(i == -i) { j++; } } Console.WriteLine(j); Console.Read(); }}
Cosa viene visualizzato a console?
A. 2
B. 1
C. 0
Siete sicuri? :-)
using System;class Base{ public Base() { Method(); } public virtual void Method() { Console.WriteLine("I'm the Base"); }}class Derived: Base{ public Derived() { Method(); } public override void Method() { Console.WriteLine("I'm the Derived"); }}class Foo{ static void Main() { Derived d = new Derived(); d.Method(); Console.Read(); }}
Cosa viene visualizzato a console?
A.I'm the DerivedI'm the Derived
B.I'm the DerivedI'm the DerivedI'm the Derived
C.I'm the BaseI'm the DerivedI'm the Derived
Il quiz è ispirato da questo post di Stephen Dunn (da leggere anche tutti i "Next in topic"), post a sua volta ispirato da questa regola FxCop.
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! :-)
Adesso che avete giocato col quiz di Gianluca, vediamo se è rimasta qualche sorpresa sul fondo del sacco :-)
using System;class Foo{ static void Main() { Console.WriteLine(Test()); Console.Read(); } static int Test() { int i; try { i = 1; return i; } finally { i = 2; } i = 3; return i; }}
Vi aspettate:
A. 1
B. 2
C. 3
Un quiz bellissimo, firmato Brad Abrams:
Will this code throw an ArgumentNullException? and why?string firstName = null;String.Format (“{0}”, firstName);
Non cliccate qui prima di dare la risposta :-)
using System;class Foo{ static void Main() { int i, j; i = j = 0; i += i = 1 * i++; j += j = 1 * ++j; Console.WriteLine("{0} {1}", i, j); Console.ReadLine(); }}
Vi aspettate:
A. 1 1
B. 1 0
C. 0 1
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...
using System;class Foo{ public static bool operator true(Foo f) { return false; } public static bool operator false(Foo f) { return true; }}class Bar{ static void Main() { if(new Foo()) { Console.WriteLine("Hello world!"); } else { Console.WriteLine("Ciao mondo!"); } Console.ReadLine(); }}
Vi aspettate:
A. non compila
B. Hello world!
C. Ciao mondo!
using System;class Foo{ static void Main() { Random r1 = new Random(); Random r2 = new Random(); Console.WriteLine(r1.Next() == r2.Next()); Console.WriteLine(r1.Next(r1.Next()) == r2.Next(r2.Next())); Console.WriteLine(r1.Next(r2.Next()) == r2.Next(r1.Next())); Console.ReadLine(); }}
Vi aspettate:
A.FalseFalseFalse
B.TrueFalseFalse
C.TrueTrueFalse
D.TrueTrueTrue
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...
Console.WriteLine(Int16.MaxValue == (int)(4 * Double.Epsilon * Double.MaxValue * Int64.MaxValue));Console.WriteLine(Int16.MaxValue == 4 * (int)(Double.Epsilon * Double.MaxValue * Int64.MaxValue));
using System;using System.Reflection;class _1E{ class _1 { }}class _1F{ static void Main() { foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()) { foreach(MemberInfo m in t.GetMembers(BindingFlags.NonPublic)) { if(m.MemberType == MemberTypes.NestedType) { Console.WriteLine(double.Parse(((Type)m).FullName.Replace("_", ""))); } } } Console.ReadLine(); }}
Cosa scrive sulla console? :-)
using System;class Foo{ static void Main(ref string[] args) { Console.WriteLine("Hello World of ref!"); Console.ReadLine(); } static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.ReadLine(); }}
A. non compila
B. compila con warning
C. compila senza warning
A proposito del mondo dei ref, approfitto per passare questo consiglio di Brad Abrams (SLAR, p. 304):"In general by reference parameters make the APIs much harder to use and should be avoided in good library design"Chiaro che il "good library design" non c'entra nulla col "good quiz design" :-)
using System;enum Bar{ Baz}class Foo{ static void Main() { Bar b1 = (Bar)1; Bar b2 = 0; Console.WriteLine("{0} {1}", b1, b2); Console.ReadLine(); }}
Vi aspettate:
A. 1 0
B. errore
C. 1 Baz
Qui un po' di storia su Foo, Bar, Baz, Qux, Quux, Quuux, Quuuux, etc. :-)
using System;class M{ static void Main() { int i = 1; double d; try { d = 1.0/0; i = 2; d = 1/0.0; i = 3; d = 1/String.Empty.Length; } catch(DivideByZeroException e) { Console.WriteLine(i); } Console.ReadLine(); }}
Cosa scrive sulla console?
A. 1;
B. 2;
C. 3.
P.S.: l'iniziale della classe, M, è per M.rkino - sa lui perché :-)
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."
Bello il quiz di Andrea! Questo è il mio :-)
class Q1: System.NullReferenceException{ static int Main() { try { return 0 + (Q1)null; } catch(Q1 q) { throw; } } public static int operator +(int i, Q1 q) { return i + q.Message.Length; }}
Si ottiene:
A. NullReferenceException;
B. Q1;
C. StackOverflowException.
"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
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...
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. :-)
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))
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?
Vorrei arrivare al giorno in cui l'Italia sarà guidata da un premier:
donna
indiana
che parla con accentocome l'India che fra poco sarà guidata da un premier:
donna
italiana
che parla con accento.
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
Non immaginavo che Brad Abrams fosse così giovane... 'Sti ragazzini... :-)
Un altro esempio di Strategy (pp. 315-323 in GoF), continuando questa serie di post: 1, 1.1, 2, 3, 3.1, 4, 4.1, 4.2, 5:- System.Collections.Hashtable fa la Context;- System.Collections.IHashCodeProvider e System.Collections.IComparer fanno le Strategy;- le classi che implementano System.Collections.IHashCodeProvider e System.Collections.IComparer fanno le ConcreteStrategy;- i metodi GetHashCode e rispettivamente Compare fanno gli AlgorithmInterface;- i metodi protetti GetHash e rispettivamente KeyEquals fanno i ContextInterface
In questa pagina, un haiku .NET ogni 10 secondi :-) Alcuni sono bellissimi:
Live .NET by dayLive and love C# by nightLaugh, VB.NET-- Jason Masterman
Worlds collide, stars fallThe path must be found quicklyReader-Writer lock-- Dan Sullivan
System.ObjectNeither interface nor classJust the root, alas!-- Don Box
Classes are fancyBut not really sufficientAttributes make whole-- Dan Sullivan
I once had a dreamlanguage no longer dividesA type system binds-- Don Box
Need code but not now?Look around you and decideReflection.Emit()-- Dan Sullivan
".class public A"I love you ILDASMAll but source revealed-- Craig Andera
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...