Generics e i ... presunti "paradossi"

Il polimorfismo e le interfaccie sono senza dubbio una degli aspetti più interssanti della programmazione OOP... sebbene spesso vogliamo dare ai comportamenti di una classe e/o di un interfaccia degli aspetti quasi umani ci dobbiamo convincere che quelli che noi chiamiamo comportamenti sono contratti definiti da tanto di vTable e tecnicismi correlati ....questo per dire che non è sufficiente che una classe abbia per nome e firma gli stessi comportamenti definiti da un interfaccia per essere castabile in quell'interfaccia... la classe deve comunque avere nella sua definizione (nel suo contratto) quell'interfaccia... per alcuni questa affermazione può sembrare banale... quasi scontata, ma con i generics - in alcune casistiche - ecco che l'ovvietà di cui sopra diventa una vera e propria scocciatura! (?)

Guardiamo l'esempio qui sotto illustrato. B deriva da A ma l'enumeratore genrico tipizzato di B sebbene ha intrinsecamente il comportamento di un enumeratore generico tipizzato su A... i due enumeratori non hanno nulla a che spartirsi se non l'origine comune!

Se come San Tomasso volessi fare le prove usando "Fruit" (A) e "Apple" (B) definiti nel post "Come ti sommo le pere con le mele" potremo facilmente constatare che il casting non è possibile... ne implicito, bloccato da un ferreo odioso ma corretto compilatore ...

e neppune è possibile un casting esplicito... bloccato - ancor peggio - a runtime

Come potremmo uscire?! Beh se l'oggetto non è castabile ma ha il comportamente equiparabile possiamo giocarcela con la trasformazione (un enumetaore di Apple è convertibile in enumeratore di Frutti)... per cui ecco una soluzione che fa uso dell'incapsulamento...

Definisco un enumerator generico come quello che segue

 class Enumerator<T, K>: IEnumerator<T> where K :T
 {
  IEnumerator<K> enumerator;
  
  public Enumerator(IEnumerable<K> enumerable)
  {
   this.enumerator = enumerable.GetEnumerator();
  }
  
  #region IEnumerator<T> Members
  T IEnumerator<T>.Current
  {
   get{return this.enumerator.Current;}
  }
  #endregion
  
  #region IDisposable Members
  void IDisposable.Dispose()
  {
   this.enumerator.Dispose();
  }
  #endregion
  
  #region IEnumerator Members
  object System.Collections.IEnumerator.Current
  {
   get { return this.enumerator.Current; }
  }
  
  bool System.Collections.IEnumerator.MoveNext()
  {
   return this.enumerator.MoveNext();
  }
  
  void System.Collections.IEnumerator.Reset()
  {
   this.enumerator.Reset();
  }
  #endregion
 }

...che applicato al nostro caso suona così:

 IEnumerator enumerator;
 IEnumerator<Fruit> enumFruits = fruits.GetEnumerator();
 IEnumerator<Apple> enumApples = apples.GetEnumerator();
 enumerator = enumApples;
 //enumFruits = (IEnumerator<Fruit>)enumApples;
 enumFruits = new Enumerator<Fruit, Apple>(apples);

Se qualcuno pensa che questa complicazione sia solo odiosa burocrazia... ecco cosa si potrebbe scrivere se non ci fosse impedito!

Collection<Pear> pears = new Collection<Pear>();
// Sarebbe possibile aggiungere mele in cestino tipizzato per SOLE pere!!
((Collection<Fruit>) pears).Add(new Apple());

Nel prossimo post vedo di mostrare come ho usato l'enumeratore qui definito per dare una soluzione più OOP a "Come ti sommo le pere con le mele".

posted @ giovedì 18 maggio 2006 01:18

Print

Comments on this entry:

# Limitazioni Dei Generics Nel C Sharp20

Left by Pingback/TrackBack at 18/05/2006 12:03
Gravatar
Nel C#2.0 non è possibile definire conversioni o relazioni di ereditarietà tra tipi ottenuti istanziando tipi generici anche se a partire da tipi tra loro in relazione di ereditarietà.

# re: Generics e i ... presunti "paradossi"

Left by M.rkino at 21/05/2006 03:31
Gravatar
Comments have been closed on this topic.
«aprile»
domlunmarmergiovensab
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011