Blog Stats
  • Posts - 16
  • Articles - 0
  • Comments - 123
  • Trackbacks - 31

 

giovedì 13 settembre 2007

Caricamento assemblies da percorsi alternativi

Sto sviluppando un’applicazione che è una estensione di un’applicativo , il tutto in managed c++. Per caricare i miei assemblies di varie funzioni specializzate, avevo usato la strada della GAC e quella della modifica application.exe.config.

Soluzione1 non bella, perchè queste dll non erano poi cosi’ tanto generalpurpose e poi mi potevano interferire con altre installazioni.

Soluzione 2 non bella perchè andavo a modificare dei file proprietari dell’applicativo, ad un suo re-install venivano perse le mie modifiche.  Ho trovato in rete la soluzione 3, la riassumo J  

Nella fase di caricamento : prendo il dominio corrente dell’applicazione e metto un gestore dell’evento di errore nel caricamento degli assemblies:

AppDomain^ currentDomain = AppDomain::CurrentDomain;

currentDomain->AssemblyResolve +=

          gcnew System::ResolveEventHandler( &miaclasse::MyResolveEventHandler);

 

e poi lo gestisco, andando a prendere l’assembly proprio nella mia dir:

 

System::Reflection::Assembly ^ miaclasse::MyResolveEventHandler(Object^ sender, ResolveEventArgs^ args)

{      //------ qui prendo il mio percorso di installazione dei miei componenti  

//e lo metto in String^ path -------

 

//nome dell’assembly da caricare

       String^ strTempAssmbPath=args->Name->Substring(0,args->Name->IndexOf(","))+".dll";

 

//percorso completo

       String^ fullPath = System::IO::Path::Combine(path, strTempAssmbPath);

      

//carico il tutto e lo ritorno !

       Assembly^ MyAssembly = Assembly::LoadFrom(fullPath);

       return MyAssembly;        

 

 }

 

Funziona!

lunedì 16 luglio 2007

[70-553] – 1. Section 1 – 3 Implementing serialization – 3 – Files and folders

Nella gestione dei file e delle directory, in  System.IO,  si utilizzano principalmente: File, FileInfo, Directory, Directory Info e la DriveInfo.  La DriveInfo è bella perchè da un sacco di informazioni sul disco:

          DriveInfo d = new DriveInfo("d:\\");

            String info = "Drive: " + d.Name +

                "Drive Format " + d.DriveFormat +

                "\nDrive Type " + d.DriveType +

                "\nVolume " + d.VolumeLabel +

                "\nTotal Size " + d.TotalSize.ToString() +

                "\nAvailable FreeSpace " + d.AvailableFreeSpace.ToString() +

                "\nTotal Free Space " + d.TotalFreeSpace.ToString();

            Console.WriteLine(info);

dove DriveType indica CDRom, Fixed, Network, Removable,Ram,.. e DriveFormat  dice NTFS or FAT32.

Interessante anche il FileSystemWatcher per le notifiche, su cui c’e’ anche un post di Mirko Gatti, http://blogs.ugidotnet.org/mitch/archive/2006/09/22/48513.aspx   . Confesso che con il framework 2.0 nei miei test questo non ho verificato l’errore in creazione, ma in un caso di copia di file.

Per giocare un po’ mi sono fatta una funzioncina di utilità che copia tutta una directory e assegna a tutti i file  e directory una certa data di creazione/ultima modifica. Questa me la metto in una console application e do’ il risultato il pasto al setup e ho tutte le cose belle ordinate. Magari c’e’ un’opzione da qualche parte che lo fa da solo, pero’ con questa ci posso poi mettere dei filtri e saltare alcuni tipi di file...

        private static void CopyAll(string from, string to, DateTime  date)

        {

            //dati delle directory di partenza

            DirectoryInfo dFrom = new DirectoryInfo(from);

            //dati delle directory di destinazione

            DirectoryInfo dTo = new DirectoryInfo(to);

 

            if (!dTo.Exists)

            {

                //ricreo la directory           

                System.IO.Directory.CreateDirectory(to);

                dTo.CreationTime = date;  //metto le date di creazione, modifica

                dTo.LastWriteTime = date;

            }

 

            //leggo tutti i file

            FileInfo[] files = dFrom.GetFiles();

            foreach (FileInfo f in files)

            {

                //copio il file

                string newFile = System.IO.Path.Combine(to, f.Name);

                System.IO.File.Copy(f.FullName, newFile );               

                FileInfo fNew = new FileInfo(newFile);

               

                //determino se è readonly

                bool bReadOnly = (fNew.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;

 

                //se è readonly .. tolgo l'attributo

                if (bReadOnly)   fNew.Attributes = fNew.Attributes ^ FileAttributes.ReadOnly; 

               

 fNew.CreationTime = f.CreationTime; //assegno data di creazione originale

                fNew.LastWriteTime = date; //assegno date di ultima modifiche/accesso

                fNew.LastAccessTime = date;

               

                //se occorre rimetto a posto il readonly

                if (bReadOnly)  fNew.Attributes = fNew.Attributes ^ FileAttributes.ReadOnly;  

            }

 

            //vado in ricorsione per le directory

            DirectoryInfo[] dir = dFrom.GetDirectories();

            foreach (DirectoryInfo d in dir)

                CopyAll(d.FullName, System.IO.Path.Combine(to, d.Name), date);

 

        }

 

Per completare il lavoro serve una funzione di DeleteAll della directory di destinazione, prima di iniziare la copia.

Se ci sono file ReadOnly non ci  si puo’ limitare ad usare dTo.Delete(true), viene un’eccezione.. occorre andare a togliere l’attributo.

domenica 15 luglio 2007

[70-553] – 1. Section 1 – 3 Implementing serialization – 2 – Control Xml Serialization

Gioco  un po’ quello che c’e’ in System.Xml.Serialization, anche perchè in TV non c’e’ (al solito) nulla di umano da vedere... ed il resto (saggio) della famiglia dorme.

 

La classe per serializzare è XmlSerializer, che si avvale di una bella dose di attributi sulle proprietà delle classi , es.

XmlRootAttribute : elemento radice dell’oggetto

XmlElementAttribute = elemento xml classico

XmlAttributeAttribute= elemento di tipo attributo

E i suoi amici.. XmlTextAttribute, XmlTypeAttribute, XmlEnumAttribute.., XmlArray

(ci sono anche per soap e si chiamano SoapAttributeAttribute, SoapEnumAttribute....).

   [XmlRootAttribute("IlMioOggetto", Namespace = "http://www.bruna.com", IsNullable = false)]

    public class mioOggetto2

    {

        [XmlAttributeAttribute]

        public string id;

        [XmlElementAttribute( IsNullable = false, DataType="string"  )]

        public  string nome;       //se sono private non si serializzano       

        [XmlElementAttribute] //è cmq il default

        public string cognome;

        [XmlElementAttribute(ElementName="Eta", DataType="int")]

        public int eta;

        [XmlArray]

        public List<string> nipotini;

 

        public mioOggetto2()

        {

            // questo è necessario perchè altrimenti XmlSerializer si rifiuto di inizializarsi

        }

        public mioOggetto2(string n, string c, int e)

        {

            id = System.Guid.NewGuid().ToString();

            nome = n;

            nipotini = new List<string>();

            eta = e;

        }

        public  void addNipote(string nome) { nipotini.Add(nome); }

 }

 

E si utilizza in un bel xmlSerializer

        static void Main(string[] args)

        {

            mioOggetto2 obj1 = new mioOggetto2("Donald", "Duck");

            obj1.addNipote("Qui"); obj1.addNipote("Quo"); obj1.addNipote("Qua");

               

            XmlSerializer ser = new XmlSerializer(typeof(mioOggetto2));

            TextWriter txtW = new StreamWriter("c:\\temp\\serialize1.xml");

            ser.Serialize(txtW, obj1);

            txtW.Close();               

        }

Ed il risultato è:

<?xml version="1.0" encoding="utf-8" ?>

- <IlMioOggetto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="43e35b0b-e94f-47f7-a2eb-9e4db3c682e1" xmlns="http://www.bruna.com">

  <nome>Donald</nome>

  <Eta>0</Eta>

- <nipotini>

  <string>Qui</string>

  <string>Quo</string>

  <string>Qua</string>

  </nipotini>

  </IlMioOggetto>

 

 

E per rileggere? Nel main:

 

            XmlSerializer ser2 = new XmlSerializer(typeof(mioOggetto2));

            TextReader txtR = new StreamReader("c:\\temp\\serialize1.xml");

            mioOggetto2 m = (mioOggetto2) ser2.Deserialize(txtR);

 

E avro’ tutto a posto..

Un esempio molto bello,  c’e’ nell’MSDN  in c++ , nella classe XmlSerializer.

 

venerdì 13 luglio 2007

[70-553] – 1. Section 1 – 3 Implementing serialization – 1 – Serialize or deserialize

Rimettiamoci a studiare dopo un po’ di vacanza e un po’ di eccessivo lavoro (tanto per bilanciare).

 

Serialize or deserialize an object or an object graph using runtime serialization techniques (System.Runtime.Serialization namespace)

Le interfacce di serializzazione permettono di controllare tutto il processo e per implementarle è necessario implementare l’interfaccia ISerializable,  che espone il metodo GetObjectData in cui viene effettuato il lavoro.

Ci provo:

    [Serializable]                //senza questo non va nulla

    public class mioOggetto : ISerializable, IEquatable<mioOggetto >

    {  private string nome;

        private string cognome;

        public mioOggetto(string n, string c)

        {

            nome = n;

            cognome = c;

        }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)

        {

            info.AddValue("AttributoNome", nome);

            info.AddValue("AttributoCognome", cognome);    

        }

 

        #region IEquatable<mioOggetto> Members

        public bool Equals(mioOggetto obj2)

        {

            if (obj2.nome == nome && obj2.cognome == cognome )              return true;

            else  return false;

        }

        #endregion

     }

 

Per la serializzazione ho bisogno di un oggetto che implementa l’interfaccia IFormatter, per esempio System.Runtime.Serialization.Formatters.Soap.SoapFormatter , e anche di uno stream cosi’ me lo salvo su disco e controllo il risultato.

       static void Main(string[] args)

        {

            mioOggetto obj1 = new mioOggetto("Donald","Duck");

            mioOggetto obj2 = new mioOggetto("Mickey","Mouse");

 

            IFormatter fmt = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

            System.IO.Stream stream = new System.IO.FileStream("c:\\temp\\testSerialize.xml", System.IO.FileMode.OpenOrCreate   );

            fmt.Serialize( stream, obj1);

            fmt.Serialize( stream, obj2);

            stream.Close();

}

 

Il risultato è un file file xml..cosi’:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" …….. /">

<SOAP-ENV:Body>

<a1:mioOggetto id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Test3/Test3%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">

<AttributoNome id="ref-3">Donald</AttributoNome>

<AttributoCognome id="ref-4">Duck</AttributoCognome>

</a1:mioOggetto>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

<SOAP-ENV:……..

 

Per  deserializzare  il gioco è praticamente identico.. ho bisogno di un altro SoapFormatter e gli dico di deserializzare, aggiungo al mio main le seguenti righe...

      IFormatter fmt2 = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();

      System.IO.Stream stream2 = new System.IO.FileStream("c:\\temp\\testSerialize.xml", System.IO.FileMode.Open    );

      mioOggetto  ret1 = (mioOggetto) fmt2.Deserialize(stream2);

      mioOggetto  ret2 = (mioOggetto) fmt2.Deserialize(stream2);

 

      if (ret1.Equals( obj1) )       Console.Write("Bene.");

      if (ret2.Equals( obj2) )       Console.Write("..bene!");

 

Ma attenzione, il gioco non è finito, se si prova il tutto cosi’ la funzione Deserialize si imbufalisce perchè dice che non ha il costruttore adeguato per la classe. La soluzione? Ovvia, quando la si è scoperta: aggiungere il costruttore  che prende gli stessi parametri della GetObjectData e fa il lavoro inverso. Cosi’:

       public mioOggetto( SerializationInfo info,  StreamingContext cnt)

        {

            nome = info.GetString ("AttributoNome") ;

            cognome = info.GetString ("AttributoCognome");

        }

 

Ci sono altre interfacce per controllare la serializzazione:

IDeserializationCallback: indica la classe deve essere richiamata quando la deserializzazione dell’intero insieme degli oggetti è completata.

IFormatterConverter: fornisce la connessione fra SerializationInfo e la classe formatter, in genere utilizzata per fare il parsing dei dati all’interno delle Info.

IObjectReference: indica che la classe è il riferimento ad un altro oggetto

ISerializationSurrogate: utilizzata per permettere ad un oggetto di effettuare la serializzazione di altri, magari logicamente dipendenti.

 

lunedì 2 luglio 2007

[70-553] – 1. Section 1 – 1. Dev application – 4 – Standard interfaces

Implement .NET Framework interfaces to cause components to comply with standard contracts

 

E’ buona norma uniformare il comportamento delle proprie classi a quelli degli oggetti standard del framework, in tal modo l’uso nell’applicazione non è un “caso speciale”, ma è assolutamente coerente con il resto. Ci sono percio’ delle interfaccie pensate apposta:

IComparable: ha un unico metodo CompareTo per effettuare controlli ed ordinamenti , l’ho usata in  [70-553] – 1. Section 1 – 1. Dev application – 1 – Manage data (4)

IDisposable: definisce il metodo Dispose per gestire una eventuale disallocazione specifica e dettagliata delle risorse.

IConvertible: permette di definire diversi metodi di conversione della classe in interi, stringhe, date..etc..

ICloneable: per avere un metodo Clone che copia l’oggetto in ogni sua parte

INullableValue: per avere il metodo IsNull, per indicare che una istanza (magari di tipo valueType) è nulla. Es. ObjectId nell’Autodesk DOTNETARX  ha il metodo IsNull per indicare identificativo nullo, è un metodo che semplicemente controlla che l’identificativo interno dell’id sia ancora al valore 0, iniziale, generato dal costruttore di default.

IFormattable: ha il metodo ToString().. quindi alcuni giorni fa avrei dovuto usarlo...

IEquatable: ha il metodo Equals per contollare che due oggetti siano da considerare uguali.

 

Nei miei testi, per controllare che due punti siano uguali, non è possibile controllare che x,y,z siano identici, perchè puo’ succedere che qualche cifra decimale da un certo punto poi sia differente, soprattuto in caso di operazioni matematiche.

Definisco allora che la classe implementi l’interfaccia IEquatable per effettuare l’operazione di compare: due punti sono identici se la loro distanz a è sotto una certa soglia.

 

   public struct PuntoStruct: IComparable < PuntoStruct >, IEquatable<PuntoStruct>, IFormattable

   {

       private double _x, _y, _z;

       public PuntoStruct(double x1, double y1, double z1)

      ……

       public bool Equals(PuntoStruct other)

       {

         double d = Math.Sqrt(Math.Pow(_x - other._x, 2.0) +

        Math.Pow(_y - other._y, 2.0) +

        Math.Pow(_z - other._z, 2.0));

         return (d < 0.0001);

       }

   }

Che si usa :

    PuntoStruct p0 = new PuntoStruct(0, 0, 0);

    PuntoStruct p1 = new PuntoStruct(0.000001, 0.000001, 0.000001);

    PuntoStruct p2 = new PuntoStruct(2, 4, 3);

    if (p1.Equals(p0))

        Console.WriteLine(" ( {0} ) == ( {1} )  ", p0.ToString(), p1.ToString());

           

    if (p2.Equals(p0))

        Console.WriteLine(" ( {0} ) == ( {1} )  ", p0.ToString(), p2.ToString());

 

 

E’ chiaro che p1 viene considerato identico a p0, perchè la loro distanza è sotto la soglia di 0.0001,

mentre p2 è diverso da p0!

venerdì 29 giugno 2007

[70-553] – 1. Section 1 – 1. Dev application – 3 – Generic collections

Improve type safety and application performance by using generic collections (System.Collections.Generic namespace)

 

Si tratta delle nuove collezioni, basate sui tipi generici e che quando vengono instanziate  “acquisiscono” i tipi. Sono quindi implicitamente piu’ sicure di quelle tradizionali perchè una collezione di un certo tipo potrà contenere solo elementi di quel tipo, non elementi differenti. Nelle collezioni tradizionali questo non era vero,  erano omogenee solo per il tipo di base (Object), ma in pratica potevano contenere pere/mele/rinoceronti in modo indistinto. Le collezioni sono anche piu’ performanti perchè non fanno boxing/unboxing con un bel risparmio di risorse.

Le interfacce sono le stesse delle altre collezioni: ICollection, IComparer, IDictionary, IEnumerable, IEnumerator, IEqualityComparer, IList, ma sono generiche es. IList<T>.

 

System.Collection.Generics                            System.Collection

             Dictionary                                                 Hashtable

                   List                                                       Arraylist

                Queue                                                       Queue

                  Stack                                                       Stack

             SortedList                                                   SortedList

         

C’e’ anche una LinkedList , lista bilincata, i cui elementi sono LinkedListNode.

    LinkedList<PuntoStruct> mieiPunti = new LinkedList<PuntoStruct>();

    mieiPunti.AddFirst(new PuntoStruct(1, 1, 1));

    mieiPunti.AddLast (new PuntoStruct(3,3, 3));

          

    //inserisco nella seconda posizione un nuovo punto

    LinkedListNode<PuntoStruct> pRef = mieiPunti.First;

    mieiPunti.AddAfter(pRef, new PuntoStruct(2, 2, 2));

 

    foreach (PuntoStruct p in mieiPunti)

          Console.WriteLine(p.ToString());

giovedì 28 giugno 2007

[70-553] – 1. Section 1 – 1. Dev application – 2 – Group of data(2)

Manage a group of associated data using collections (System.Collections namespace)

Classi: Le classi non fanno che implementare le interfacce.:

ArrayList, implementa:  IList, ICollection, IEnumerable, ICloneable

Hashtable: implementa IDictionary, ICollection, IEnumerable, ICloneable .. e qualche altra interfaccia non di liste per la serializzazione e deserializzazione;

CollectionBase: è una classe astratta per collezioni fortemente tipizzate. Implementa IList, ICollection, IEnumerable.

Per usarla si deve creare una propria classe derivando da quella..

ReadOnlyCollectionBase: è una classe astratta per una collezione che, dopo la fase di creazione, diventa read-only

DictionaryBase: è la classe astratta per un dizionario: insieme di coppie chiave-valore.

DictionaryEntry: è la classe per definire la coppia chiave – valore.

Queue: è una lista tradizionale (FIFO), implementa ICollection, IEnumerable, Icloneable.

SortedList: è una sorta di dizionario ordinato per chiave, accessibile sia per chiave che per indice. Implementa:  ICollection, IEnumerable, ICloneable

BitArray: gestisce in modo compatto un array di bit. Implementa ICollection, IEnumerable, ICloneable.

Stack: è la classica lista LIFO. Implementa:  ICollection, IEnumerable, ICloneable

Comparer: serve per paragonare due oggetti, il costruttore puo’ prende la cultura come parametro. C’e’ anche una bella classe CaseInsensitiveComparer bello per paragonare le stringhe

mercoledì 27 giugno 2007

[70-553] – 1. Section 1 – 1. Dev application – 2. Group of data(1)

Manage a group of associated data using collections (System.Collections namespace)

Interfacce:

ICollection: è l’interfaccia per quasi tutte le liste: struttura l’interfaccia per inserire un elemento, per inserire un elemento in una posizione, per avere il conteggio e un enumerator che funziona come iteratore, che implementa l’intefaccia IEnumerator.

IComparer: è un’interfaccia che espone solo in metodo Compare per personalizzare il confronti fra gli oggetti della collezione.

IDictionary: è l’interfaccia per una collezione di coppie “chiave – valore”, prevede funzioni come Add, Contains, Clear e la scansione con un IDictionaryEnumerator.

IEnumerable è una interfaccia ha solo una funzione che ritorna un IEnumerator. Il bello di una classe che implementa questo tipo di interfaccia è che si puo’ utilizzare l’enumerator in un foreach rendendo il tutto molto molto semplice nell’uso.

Se si usa un IEnumerator è necessarissimo utilizzare  yield per restituire i valori.

   public class Mesi : System.Collections.IEnumerable

   {

      string[] _mesi = {"Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dec"};

      public System.Collections.IEnumerator GetEnumerator()

      {

         for (int i = 0; i < _mesi.Length; i++)

         {

            yield return _mesi[i];

         }

       }

    }

 

E si usa:

            Mesi mieimesi = new Mesi();

            foreach (string s in mieimesi)

                Console.Write(" {0} ", s);

 

IEqualityComparer: è una interfaccia per soli metodi: Equals e GetHashCode.

IHashCodeProvider: è un interfaccia per definire una propria funzione Hash

IList: E’ l’interfaccia per una lista di oggetti: Add, Insert, getIndexOf,Remove,

(ICloneable è l’interfaccia per ottenere una copia dell’oggetto)

martedì 26 giugno 2007

[70-553] – 1. Section 1 – 1. Dev application – 1 – Manage data (5 fine!)

Manage data in a .NET Framework application using .NET Framework 2.0 system types (System namespace)

Eccezioni:  System.Exception è la classe base di tutte le eccezioni ed interrompono il flusso normale di lavoro dell’applicazione per un errore.  Un’eccezione viene gestita dall’applicazione o dal gestore degli errori predefiniti.

Riassumento le eccezioni si  intercettano con Try- Catch, dove il catch puo’ essere catch(1), catch(2)... per distinguere a priori su diversi tipi di eccezioni e prenderle in modo gerarchizzato...

 Dopo il blocco Try-Catch il Finally viene sempre eseguito, in genere utilizzato per liberare risorse.

C’e’ un ApplicationException che indica un errore irreversibile, ma la guida consiglia di derivare le proprie eccezioni da System.Exception.

Per generare un’eccezione si usa:   throw new myException(..parametri); 

http://msdn2.microsoft.com/it-it/library/system.exception(VS.80).aspx

 

Boxing/Unboxing. E’ la tecnica con cui si passano da ValueType a ReferenceType. 

object  o = i;                 BOX:  dove i è il classico intero o un altro valueType

int i = (int)o;       UNBOX: per ottenere il valore indietro.

 

Ma per sapere cosa c’e’ dentro ad un oggetto..          if (o is int)....

 

http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=38

 

 

TypeForwardedToAttribute: specifica un tipo che si trova in un altro assembly e serve per riorganizzare la posizione delle classi negli assembly senza dover modificare i chiamanti e quindi l’intera applicazione L’idea è semplice

 stato iniziale:

·         In un assembly A c’e’ una classe X con i suoi metodi

·         Altri assembly dell’applicazione  utilizzano la classe.

Dopo la ristrutturazione:

·         In un assembly B c’e’ la classe X con i suoi metodi, stesso namespace

·         Dall’assembly A è stata CANCELLATA la classe X

·         Nell’assembly A è stata inserito il riferimento all’assembly B

·         Nell’assembly A è stata messa una direttiva del tipo:

 

    [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(mionamespace.X)]

 

·         Nell’applicazione vengono messi i due nuovi assembly A e B

·         L’applicazione non viene ricompilata, continua a pensare di guardare la libreria A, quest'ultima fa poi la ridirezione a B.           

 J A me  ricorda il concetto della dichiarazione extern, anche se quella era solo per la compilazione, non per il runtime.

 

http://msdn2.microsoft.com/en-us/library/system.runtime.compilerservices.typeforwardedtoattribute.aspx

lunedì 25 giugno 2007

[ 70-553 ] – 1. Section 1 – 1. Dev application – 1 – Manage data (4)

Manage data in a .NET Framework application using .NET Framework 2.0 system types (System namespace)

Generics:   fanno riferimento a classi e metodi che lavorano allo stesso modo su differenti tipi di oggetti. Quando vengono istanziati, necessitano sempre di un tipo di dati, cosi’ da dargli un “preciso significato”  e rappresentano l’implementazione in C# dei template del C++.  

Uno dei vantaggi  dei generics è quello di far risparmiare sul boxing/unboxing:  la collezione generica “List” è l’equivalente di “ArrayList”, se ci mettiamo degli interi o dei double o un altro valueTypes non c’e’ boxing per inserire i dati e unboxing per leggere,  cosa decisamente apprezzabile in termini di performance. 

Gli esempi in rete implementano tutti gli stack.

Allora faccio una lista :

public class myList1< T >  {

      ….

      public void Add(T newValue) {…….}

}

 

E la cosa bella è che in una lista di interi dichiarata con non ci posso mettere dei double e fare confusione.  :-)

Voglio pero’ fare in modo che la lista sia sempre ordinata, indipendentemente dal tipo di contenuto. Faccio una lista 2 e gli dico che il tipo T, implemente l’interfaccia IComparable, cosi’ che poi posso fare una funzione di Add sfrutti il metodo CompareTo. (I tipi di base sono tutti derivati da IComparable!).

        public class myList2<T> where T : System.IComparable<T>

        {

            const int minSize = 10;

            private T[] myData  = new T[minSize];

            private int size=0;

 

            public void Add(T newValue)

            {   //tralascio tutti gli oggetti piu' piccoli

                int destPos = 0;               

                for (; destPos < size && myData[destPos].CompareTo(  newValue)< 0; destPos++) ;

                //sposto tutti quelli piu' grandi

                for (int moveThis = size-1; moveThis >= destPos; moveThis--)

myData[moveThis + 1] = myData[moveThis];

                //inserisco nel posto libero il mio

                myData[destPos] = newValue;

                //aggiorno la dimensione ed eventualmente allargo l'array

                size++;

                if (size == myData.Length) enlargeArray();

            }

 

            public void Display(string msg)

            {

                Console.WriteLine(msg);

                for (int i = 0; i < size; i++)

                    Console.WriteLine(myData[i].ToString() + " ");               

            }

            public void enlargeArray()  {...}

           

        }

Deve andare con i tipi di base, con i double, con qualsiasi cosa che implementi l’IComparer, anche un ValueType. Modifico la classe PuntoStruct di alcuni giorni fa:

        public struct PuntoStruct: IComparable < PuntoStruct >

        {

            private double _x, _y, _z;

 

            public PuntoStruct(double x1, double y1, double z1) {…}

            

            public int CompareTo( PuntoStruct other)

            {

 //faccio un ordinamento solo per X, tanto per provare

                return (_x.CompareTo(other._x));

            }

 

            public override  string ToString() {

return (string.Format("x = {0}, y ={1}, z = {2}",  _x, _y, _z));  }

        };

 

 

Se la uso posso istanziare tranquillamente  sia una lista di interi:

 

            myList2<int> lista2 = new myList2<int>();

 

che una lista dei miei punti

 

            myList2<PuntoStruct > listaPunti = new myList2<PuntoStruct>();

 

 

 

Copyright © Bruna Gavioli