Ricordate l'idiomatica soluzione per sommare Pere e Mele descritta in "Come ti sommo le pere con le mele"?
Soluzione interessante anche se mi era poco soddisfacente perchè poco pulita ( e poco OOP) e troppo legata a potenzialità del linguaggio.
La problematica di trovate qualcosa di soddisfacente era sopratutto legata/limitata ai "limiti dei Generics di C# 2.0": "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à." (UGIdotNETWiki). La nuova soluzione è frutto di una più attenta analisi dei requisiti del caso d'uso/funzionalità. Nella prima soluzione volevo sommare esplicitamente due collezioni di frutta "public static Fruits operator +(Fruits a, Fruits b)" ma a pensarci bene NON è necessario avere esattamente una collection come secondo operatore (b) e la vera necessità è che l'oggetto da sommare possa semplicemente enumerare frutti.
interface IFruitEnumerable : IEnumerable<Fruit> { }
Ecco quindi come si potrebbe ri-definire la collezione generica di frutti e in particolare l'overload dell'operatore "+".
class Fruits : Collection<Fruit>
{
public Fruits() { }
private Fruits(IList<Fruit> list) : base(list) { }
public static Fruits operator +(Fruits a, IFruitEnumerable b)
{
List<Fruit> list = new List<Fruit>();
list.AddRange(a);
list.AddRange(b);
return new Fruits(list);
}
}
Prima di proseguire rimando al post "Generics e i ... presunti paradossi" di cui useremo la classe Enumerator<T, K> ivi definita. Poi ri-definirò le collezioni "Apples" e "Pears" eliminando l'implementazione dell'overload del casting implicito e facendo implementare loro l'interfaccia IFruitEnuemarable. Nell'implementazione delle due collection ho usanto due diverse "strategie"/soluzioni equivalenti come descritto dal diagramma di classi qui sotto riportato.
Riporto ora il codice. È omessa la definizione di "Fruit", "Apple" e "Pear" per le quali rimando alla definizione riportata nel post iniziale ("Come ti sommo le pere con le mele"?).
class Apples : Collection<Apple>, IFruitEnumerable
{
#region IEnumerable<Fruit> Members
IEnumerator<Fruit> IEnumerable<Fruit>.GetEnumerator()
{
return new Enumerator<Fruit, Apple>(this);
}
#endregion
}
abstract class BaseFruitCollection<T> : Collection<T>, IFruitEnumerable where T : Fruit
{
#region IEnumerable<Fruit> Members
IEnumerator<Fruit> IEnumerable<Fruit>.GetEnumerator()
{
return new Enumerator<Fruit, T>(this);
}
#endregion
}
class Pears : BaseFruitCollection<Pear>
{
}
Infine ecco il codice di test; lo stesso codice del post originale poichè infatti il comportamento (e quindi l'utilizzo) delle collection è rimasto invariato.
class Program
{
static void Main(string[] args)
{
Apples apples = new Apples();
apples.Add(new Apple());
apples.Add(new Apple());
apples.Add(new Apple());
Pears pears = new Pears();
pears.Add(new Pear());
pears.Add(new Pear());
Fruits fruits = new Fruits();
fruits += apples;
fruits += pears;
Console.WriteLine(fruits.Count);
Console.ReadLine();
}
}
posted @ giovedì 25 maggio 2006 11:35