DictionaryBase.cs

/*
    Questo esempio implementa una collezione Orders di coppie (OrderNumber, Order).
    La classe Orders è ottenuta derivando da DictionaryBase. Alla classe comunque 
    sono stati aggiunti i metodi Strong-Typed oltre a quelli ereditati da DictionaryBase
    ed implementati esplicitamente sulle interfaccie IDictionary, ICollection e IEnumerable.

*/

using sys = System;
using sysCols = System.Collections;


//
//-----------------------------------------------------------------------------------------------
// Key: Number
//-----------------------------------------------------------------------------------------------
//
public struct OrderNumber
{
  private static int globalNum = 1000;

  public int Year;
  public int Number;
  
  public void SetNewOrderNumber()
  {
    Year =sys.DateTime.Now.Year;
    Number = ++globalNum;
  }

  public override int GetHashCode()
  {
    return sys.String.Format("{0}-{1}", Year, Number).GetHashCode();
  }

  public override string ToString()
  {
    return sys.String.Format("{0}-{1}", Year, Number);
  }
}
//
//-----------------------------------------------------------------------------------------------
// Item: Order
//-----------------------------------------------------------------------------------------------
//
public class Order {
  private OrderNumber num;
  private string customer = "?";

  public Order() {
    num = new OrderNumber();
    num.SetNewOrderNumber();
  }

  public Order(OrderNumber number) {num = number;}

  public string Customer {
    get {return customer;}
    set {customer = value;}
  }

  public OrderNumber Number {
    get {return num;}
  }

  public override string ToString() {
    return sys.String.Format("[{0} {1}]", num, customer);
  }
}
    

//    
//-----------------------------------------------------------------------------------------------
// Collection: Orders
//-----------------------------------------------------------------------------------------------
//
public class Orders : sysCols.DictionaryBase {

  //////////////////////////////////////////////////////////////////////////////////
  // FOUNDATION MEMBERS
  //////////////////////////////////////////////////////////////////////////////////

  // Default Constructor
  public Orders() {}        

  // Copy-Constructor
  public Orders(Orders value) 
  {
    foreach(sysCols.DictionaryEntry myPair in value.Dictionary)
      this.Dictionary.Add(myPair.Key, myPair.Value);
  }


  //////////////////////////////////////////////////////////////////////////////////
  // MODIFIERS MEMBERS
  //////////////////////////////////////////////////////////////////////////////////

  // Type-safe version of IDictionary.Item
  public Order this[OrderNumber index] 
  {
    get {return ((Order)(this.Dictionary[index]));}
    set {this.Dictionary[index] = value;}
  }

  // Type-safe version of IDictionary.Add
  public void Add(OrderNumber key, Order value) {this.Dictionary.Add(key, value);}
   
  // Type-safe version of IDictionary.Remove
  public void Remove(OrderNumber key) {this.Dictionary.Remove(key);}
        
  //////////////////////////////////////////////////////////////////////////////////
  // ACCESSOR MEMBERS
  //////////////////////////////////////////////////////////////////////////////////

  // Type-safe version of IDictionary.Contains
  public bool Contains(OrderNumber key) {return this.Dictionary.Contains(key);}

  // Type-safe version of IEnumerable.GetEnumerator
  public new Orders.DictionaryEnumerator GetEnumerator() {return new Orders.DictionaryEnumerator(this);}

  // Type-safe version of ICollection.CopyTo
  public void CopyTo(Orders.DictionaryEntry[] array, int index) {
    sysCols.DictionaryEntry[] tmp = new sysCols.DictionaryEntry[array.Length-index];
    this.Dictionary.CopyTo(tmp, index);
    for(int i = 0; i < tmp.Length; ++i) {
      if (object.ReferenceEquals(tmp[i].Key, null)) break;

      array[index + i] = new Orders.DictionaryEntry((OrderNumber)tmp[i].Key, (Order)tmp[i].Value);
    }
  }        
                        
  // Type-safe version of IDictionary.Keys
  //    public sysCols.ICollection Keys {
  //      get {
  //        sysCols.IDictionary tmpDict = this;
  //        sysCols.ICollection tmpKeys = tmpDict.Keys;
  //        OrderNumberCollection[] tmpOnKeys; <- Implementare una collezione (da ReadOnlyCollectionBase) di OrderNumber strong-typed
  //        tmpKeys.CopyTo(tmpOnKeys, 0);
  //        return tmpOnKeys;
  //      }
  //    }

  // Type-safe version of IDictionary.Values
  //    public sysCols.ICollection Values {
  //      get {
  //        sysCols.IDictionary tmpDict = this;
  //        sysCols.ICollection tmpVals = tmpDict.Values;
  //        OrderCollection tmpOrdVals; <- Implementare una collezione (da ReadOnlyCollectionBase) di Order strong-typed
  //        tmpVals.CopyTo(tmpOrdVals, 0);
  //        return tmpOrdVals;
  //      }
  //    }
  

  //////////////////////////////////////////////////////////////////////////////////
  // EVENTS & DELEGATES
  //////////////////////////////////////////////////////////////////////////////////

  protected override void OnValidate(object key, object value)
  {
    if((key == null || key is OrderNumber) && (value == null || value is Order))
      return;

    throw new sys.ArgumentException("Sono permessi solo coppie di tipo (OrderNumber, Order).");
  }


  //////////////////////////////////////////////////////////////////////////////////
  // NESTED ITERATOR & C.
  //////////////////////////////////////////////////////////////////////////////////

  public struct DictionaryEntry{
    private OrderNumber kk;
    private Order vv;

    // Constructor
    public DictionaryEntry(OrderNumber key, Order value){
      kk = key;
      vv = value;
    }

    // Properties
    public OrderNumber Key { 
      get {return kk;}
      set {kk = value;}
    }

    public Order Value { 
      get {return vv;}
      set {vv = value;}
    }

    // Methods
    public override string ToString() {
      return sys.String.Format("{0} -> {1}", kk, vv);
    }

    // Conversions
    //public static implicit operator DictionaryEntry(sysCols.DictionaryEntry de) {
    //  return new DictionaryEntry((OrderNumber)de.Key, (Order)de.Value);
    //}
  }

  public class DictionaryEnumerator: sysCols.IDictionaryEnumerator
  {
    private sysCols.IDictionaryEnumerator baseEnumerator;            
            
    // CONSTRUCTOR
    public DictionaryEnumerator(Orders mapping) {
      sysCols.DictionaryBase tmp = mapping;
      this.baseEnumerator = tmp.GetEnumerator();
    }

    // ACCESSOR METHODS
    // Type-unsafe explicit interface implementation of IDictionaryEnumerator.Entry
    sysCols.DictionaryEntry sysCols.IDictionaryEnumerator.Entry {
      get{return this.baseEnumerator.Entry;}
    }
    // Type-safe DictionaryEnumerator Entry
    DictionaryEntry Entry {
      get{
        return new DictionaryEntry(Key, Value);
      }
    }

    // Type-unsafe explicit interface implementation of IDictionaryEnumerator.Key
    object sysCols.IDictionaryEnumerator.Key {get{return this.baseEnumerator.Key;}}
    // Type-safe DictionaryEnumerator Key
    OrderNumber Key {get{return (OrderNumber)this.baseEnumerator.Key;}}

    // Type-unsafe explicit interface implementation of IDictionaryEnumerator.Value
    object sysCols.IDictionaryEnumerator.Value {get{return this.baseEnumerator.Value;}}
    // Type-safe DictionaryEnumerator Value
    Order Value {get{return (Order)this.baseEnumerator.Value;}}

    // Type-safe iterator Current method 
    public DictionaryEntry Current {
      get {return Entry;}
    }           
    // Type-unsafe IEnumerator.Current
    object sysCols.IEnumerator.Current {
      get {return baseEnumerator.Current;}
      }
            
    // Type-unsafe IEnumerator.MoveNext()
    bool sysCols.IEnumerator.MoveNext() {return baseEnumerator.MoveNext();}
    // Type-safe iterator MoveNext() method 
    public bool MoveNext() {return baseEnumerator.MoveNext();}            
            
    // Type-unsafe IEnumerator.Reset()
    void sysCols.IEnumerator.Reset() {baseEnumerator.Reset();}
    // Type-safe iterator Reset() method 
    public void Reset() {baseEnumerator.Reset();}            

  } 

}



//
//-----------------------------------------------------------------------------------------------
// Main App
//-----------------------------------------------------------------------------------------------
//
class MainApp{
  public static void Main(){

    //
    // Esercito i costruttori tipizzati
    //
    Orders myOrders;
    {
      Orders tmpOrders = new Orders();

      for(int i = 0; i<10; ++i)
      {
        Order o = new Order();
        tmpOrders.Add(o.Number, o);
      }

      myOrders = new Orders(tmpOrders);
    }              

    {
      Orders myTmpOrders = new Orders(myOrders);      
      // error CS1502: The best overloaded method match for 'Orders.Orders(Orders)' has some invalid arguments
      // Scommenta la linea di codice per verificare che il costruttore tipizzato funziona
      //Orders myTmpOrders2 = new Orders(new object());      
    }
      
    //
    // Esercito l'enumeratore tipizzato
    //
    foreach(Orders.DictionaryEntry numOrdPair in myOrders)
    {
      OrderNumber tmpOn = numOrdPair.Key;
      Order tmpOrd = numOrdPair.Value;

      // error CS0029: Cannot implicitly convert type 'OrderNumber' to 'string'
      // Scommenta le linee di codice per verificare che l'Entry tipizzato funziona
      //string tmpK = numOrdPair.Key;
      //string tmpV = numOrdPair.Value;

      sys.Console.WriteLine("Entry Key: {0} \t\t Value: {1}", numOrdPair.Key, numOrdPair.Value);
    }

    // error CS0030: Cannot convert type 'Orders.DictionaryEntry' to 'string'
    // Scommenta la linea di codice per verificare che l'enumeratore tipizzato funziona
    //foreach(string numOrdPair in myOrders) {sys.Console.WriteLine(numOrdPair);}

    // Scommenta per verificare che l'enumeratore non tipizzato implementato esplicitamenete 
    // sull'interfaccia IEnumerable funziona sempre.
    //foreach(sysCols.DictionaryEntry numOrdPair in (sysCols.IEnumerable)myOrders) {sys.Console.WriteLine(numOrdPair);}

    
    //
    // Esercito i metodi tipizzati
    //
    {
      Order tmpOrd = new Order();
      myOrders[tmpOrd.Number] = tmpOrd;

      // error CS0029: Cannot implicitly convert type 'object' to 'Order'
      // Scommenta la linea di codice per verificare che il metodo tipizzato funziona
      //myOrders[tmpOrd.Number] = new object();
    }
    
    {
      Order tmpOrd = new Order();
      myOrders.Add(tmpOrd.Number, tmpOrd);
    }
    // error CS1502: The best overloaded method match for 'Orders.Add(OrderNumber, Order)' has some invalid arguments
    // Scommenta la linea di codice per verificare che il metodo tipizzato funziona
    //myOrders.Add(new object(), new object());

    {
      Order tmpOrd = new Order();
      myOrders.Add(tmpOrd.Number, tmpOrd);
      myOrders.Remove(tmpOrd.Number);

      // error CS1502: The best overloaded method match for 'Orders.Remove(OrderNumber)' has some invalid arguments
      // Scommenta la linea di codice per verificare che il metodo tipizzato funziona
      //myOrders.Remove(new object());

      sys.Console.WriteLine("Contains {0}: {1}",tmpOrd.Number ,myOrders.Contains(tmpOrd.Number));
    }

    // error CS1502: The best overloaded method match for 'Orders.Contains(OrderNumber)' has some invalid arguments
    // Scommenta la linea di codice per verificare che il metodo tipizzato funziona
    //myOrders.Contains(new object());
    
    {
      myOrders[new OrderNumber()] = null;
      Orders.DictionaryEntry[] vetPair = new Orders.DictionaryEntry[20];
      myOrders.CopyTo(vetPair, 0);
      sys.Console.WriteLine(vetPair.Length);
    }

    {
      string[] vetOrd = new string[20];
      // error CS1502: The best overloaded method match for 'Orders.Contains(OrderNumber)' has some invalid arguments
      // Scommenta la linea di codice per verificare che il metodo tipizzato funziona
      //myOrders.CopyTo(vetOrd, 0);
    }

    
    //
    // Esercito i metodi non tipizzati
    //

    sysCols.IDictionary aDict = myOrders;
    {
      Order tmpOrd = new Order();
      aDict[tmpOrd.Number] = tmpOrd;

      // Scommenta la linea di codice per verificare che l'evento OnValidate intercetta 
      // l'errore solo Run-Time
      //aDict[tmpOrd.Number] = new object();
    }

    {
      Order tmpOrd = new Order();
      aDict.Add(tmpOrd.Number, tmpOrd);
    }

    // Scommenta la linea di codice per verificare che l'evento OnValidate intercetta 
    // l'errore solo a Run-Time
    //aDict(123, "Arbracadabra")

    {
      Order tmpOrd = new Order();
      aDict.Add(tmpOrd.Number, tmpOrd);
      object tmpObj = tmpOrd.Number;
      aDict.Remove(tmpObj);
    }
  
    // Scommenta la linea di codice per verificare che l'evento OnValidate intercetta 
    // l'errore solo a Run-Time
    //aDict.Remove(new object());

    return;
  }
}


/*

  SMemorandum:

  Descrizione dei metodi usati per implementare (i) la tipizzazione forte a partire da 
  quanto ereditato (e) dalla classe base DirectoryBase:
  - (i) Orders.this[] strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.this[] di DictionaryBase implemetato esplicitamente sull'interfaccia
  - (i) Add(...) strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.Add() di DictionaryBase implemetato esplicitamente sull'interfaccia
  - (i) Remove(...) strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.Remove() di DictionaryBase implemetato esplicitamente sull'interfaccia
  - (i) Contains(...) strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.Contains() di DictionaryBase implemetato esplicitamente sull'interfaccia
  - (i) Orders.GetEnumerator() strong-typed fa l'hide col modifier new (non può fare l'Overloading
    perché non ha parametri, non può fare l'Override perché il tipo di ritorno è diverso e c'è
    già una copia (e) sull'interfaccia principale)
  - (i) CopyTo(...) strong-typed in Overload sull'interfaccia della classe (e) perchè ha parametri 
    diversi
  - (i) Keys strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.Keys() di DictionaryBase implementato esplicitamente sull'interfaccia
  - (i) Values(...) strong-typed sull'interfaccia della classe;
    (e) Orders.IDictionary.Values() di DictionaryBase implemetato esplicitamente sull'interfaccia

*/