ottobre 2006 Blog Posts
Possibile avere istanze di Foo? Tempo massimo di risposta: 30 secondi.
class Foo { public Foo(ref Foo arg) { arg = this; } }
Potrebbe andare bene per un colloquio (lo so che è semplice ma sono curioso cos'avreste risposto in 30 secondi).
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...
Un altro thread sul forum di GUISA, partendo da una frase di Janky. Solo un invito a trovare una soluzione insieme...
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!
Sul forum di GUISA ho postato qui un'implementazione del pattern State sfruttando la macchina a stati generata dal compilatore C# 2.0 per un iteratore generico. L'idea mi è venuta per gioco, diciamo che per adesso potrebbe essere interessante soprattutto per quelli che vogliono capire gli iteratori generici, non necessariamente come implementazione "seria" del pattern State.
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.
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) { ...
Senza utilizzare alcun namespace, scrivete un metodo e compilatelo in una dll in tal modo che passandogli un parametro da codice C# ritorna un risultato mentre passandogli lo stesso parametro da codice VB.NET ritorna un altro risultato. Dovete indicare anche il valore del parametro.
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#...
Stamattina ho incontrato questa frase del grande matematico ungherese George Pólya:
"If you can't solve a problem, then there is an easier problem you can solve: find it"
e ho pensato subito al refactoring pattern Compose Method:
"You can't rapidly understand a method's logic. Transform the logic into a small number of intention-revealing steps at the same level of detail"
che, volendo, ci porta al buon Divide et impera.
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...
Senza utilizzare reflection si chiede di trovare un modo per eseguire il codice del costruttore private senza parametri di una classe abstract. Troppo semplice anche questo? :-)