<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Helper e Generics</title>
        <link>http://community.dotnetwork.it/sabrina/category/6.aspx</link>
        <description>Post dedicati a classi di tipo generico, a tools e plug-in.</description>
        <language>it-IT</language>
        <copyright>Sabrina C.</copyright>
        <managingEditor>ziayeye@ziayeye.it</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <item>
            <title>Conversioni che passione</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2011/10/14/conversioni-che-passione.aspx</link>
            <description>&lt;p&gt;Ieri ho bloggato una nota per alcune conversioni poco frequenti che ho dovuto fare a causa di una routine di checksum che ho scritto per  &lt;a href="http://community.dotnetwork.it/alberto/default.aspx" target="_blank"&gt;Alberto&lt;/a&gt;. Oggi ho scoperto che la mia ottimistica versione era largamente superata dal meccanismo reale del calcolo del checksum, per riuscire a riprodurre il quale ho dovuto effettuare una serie di stranezze che vi listo di seguito nel caso abbiate la “fortuna” (poca) di scontrarvi con qualcosa di simile.&lt;/p&gt;  &lt;p&gt;&lt;font color="#0080c0" size="3"&gt;&lt;strong&gt;Leggere un sub-array da un byte array&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] sourceArray;
... &lt;span class="rem"&gt;//Qui mettete i bytes nell’array leggendo un file o una seriale&lt;/span&gt;
&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] destArray = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[desiredSublength]
Array.Copy(sourceArray, StartIndex, destArray, DestStartIndex, Length);&lt;/pre&gt;

&lt;p&gt;&lt;font color="#0080c0" size="3"&gt;&lt;strong&gt;Conversione dei bytes nei corrispondenti caratteri ascii &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;char&lt;/span&gt;[] chars = System.Text.Encoding.UTF8.GetChars(destArray);&lt;/pre&gt;

&lt;p&gt;&lt;font color="#0080c0" size="3"&gt;&lt;strong&gt;Far diventare una porzione dell’array di caratteri una string &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; subValue = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(charsArray, startIndex, length);&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;&lt;font color="#0080c0" size="3"&gt;Convertire la stringa rappresentante un numero esadecimale in un byte&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;byte&lt;/span&gt; myHexByte = Convert.ToByte(&lt;span class="str"&gt;"1C"&lt;/span&gt;, 16);&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;&lt;font color="#0080c0" size="3"&gt;Convertire un byte in una stringa rappresentante il numero in esadecimale&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; hexString = Convert.ToString(myByteValue, 16);&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;&lt;font color="#0080c0" size="3"&gt;Fate attenzione che la stringa sia correttamente upper o lower case&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; lowerHex = hexString.ToLower();
&lt;span class="kwrd"&gt;string&lt;/span&gt; upperHex = hexString.ToUpper();&lt;/pre&gt;

&lt;p&gt;Questo perché &lt;font color="#ff0000"&gt;&lt;strong&gt;db&lt;/strong&gt;&lt;/font&gt; e &lt;strong&gt;&lt;font color="#ff0000"&gt;DB&lt;/font&gt;&lt;/strong&gt; sono lo stesso numero ma cambiano completamente se &lt;strong&gt;&lt;font color="#0080c0" size="3"&gt;convertite la stringa in un char array&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;char&lt;/span&gt;[] hexLetters = upperHex.ToCharArray();&lt;/pre&gt;

&lt;p&gt;e poi  &lt;strong&gt;&lt;font color="#0080c0" size="3"&gt;convertite il char array in un byte array&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="CSharpFormat"&gt;&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] bytesFromHexLetters = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[hexLetters.Length];
&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; hexLetters.Length; i++)
{
   bytesFromHexLetters [i] = Convert.ToByte(chars[i]);
}&lt;/pre&gt;

&lt;p&gt;Provate con le lettere esadecimali in upper e lower case e ve ne accorgete, e se mi chiedete, ma tutto in una routine di calcolo del checksum? &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smilewithtongueout" alt="Con la lingua fuori" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/Windows-Live-Writer/I-Forget-the-opposite-convert-a-string-t_123E5/wlEmoticon-smilewithtongueout_2.png" /&gt;  qui lo chiamiamo Ufficio Complicazione Affari Semplici, sembra essere spesso molto affollato.&lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/900.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2011/10/14/conversioni-che-passione.aspx</guid>
            <pubDate>Fri, 14 Oct 2011 19:35:04 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/900.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2011/10/14/conversioni-che-passione.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/900.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Lezioni di &amp;ldquo;pesca&amp;rdquo; .Net in C# parte 5</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2011/05/15/lezioni-di-ldquopescardquo-.net-in-c-parte-5.aspx</link>
            <description>&lt;p&gt;Siamo arrivati alla quinta lezione di C# della serie, abbiamo concluso la gestione della nostra prima classe, la classe persona, pertanto per proseguire e presentare tutti gli aspetti di quello che si può fare con C# iniziamo a pensare a una piccola applicazione, che ci permetterà di spiegare le enumerazioni, le collezioni, l'ereditarietà, la serializzazione XML e probabilmente molte altre cose che verranno.&lt;/p&gt;  &lt;p&gt;Avendo come base la classe persona, ho deciso di creare una classe per gestire il curriculum di un programmatore con informazioni anagrafiche, un minimo di informazioni "fiscali", una collezione di competenze che descrivano quello che lui sa fare ed una collezione di lingue conosciute con la loro descrizione. In seguito magari potremo estendere ulteriormente il tutto. &lt;/p&gt;  &lt;p&gt;In questo Webcast, oltre a spiegare a grandi linee cosa faremo nelle prossime lezioni, creiamo una Enumerazione e vediamo come si usa, e creiamo la classe base Competence per descrivere le competenze del programmatore, gli aggiungiamo funzionalità e spieghiamo come salvare su disco le informazioni usando XML e spiegando le basi della serializzazione (qualcosa di non nuovo a questo blog, che però in un webcast permette di approfondire i vari concetti di base). &lt;/p&gt;  &lt;p&gt;Come sempre buona “pesca” e alla prossima lezione.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;object id="scPlayer" width="750" height="560" type="application/x-shockwave-flash" data="http://content.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/scplayer.swf"&gt;&lt;param name="movie" value="http://content.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/scplayer.swf" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;param name="flashVars" value="thumb=http://content.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/FirstFrame.jpg&amp;amp;containerwidth=750&amp;amp;containerheight=560&amp;amp;autohide=true&amp;amp;autostart=false&amp;amp;loop=false&amp;amp;showendscreen=true&amp;amp;showsearch=false&amp;amp;showstartscreen=true&amp;amp;tocdoc=float&amp;amp;xmp=sc.xmp&amp;amp;content=http://content.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/unpopiudihello05.mp4&amp;amp;blurover=false" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="scale" value="showall" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;param name="base" value="http://content.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/" /&gt;&lt;iframe type="text/html" frameborder="0" scrolling="no" style="overflow:hidden;" src="http://www.screencast.com/users/Sabrina_C/folders/DotNetWork/media/82f205a9-4880-427e-b30f-d227bcd65410/embed" height="560" width="750"&gt;&lt;/iframe&gt;&lt;/object&gt;  &lt;p&gt;Il link al &lt;a href="http://www.dotnetwork.it/LinkClick.aspx?fileticket=U_nop3WEZAE%3d&amp;amp;tabid=191&amp;amp;mid=727"&gt;codice sorgente della quinta lezione&lt;/a&gt; &lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:1937d99d-6a05-4a58-b0b1-212c64182a80" class="wlWriterEditableSmartContent"&gt;Tag di Technorati: &lt;a href="http://technorati.com/tags/C%23" rel="tag"&gt;C#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/class" rel="tag"&gt;class&lt;/a&gt;,&lt;a href="http://technorati.com/tags/enum" rel="tag"&gt;enum&lt;/a&gt;&lt;/div&gt;  &lt;p&gt;Il link al webcast se avete problemi a visualizzarlo direttamente è questo: &lt;a href="http://www.screencast.com/t/zyFquPqX6xP"&gt;Un po' piu' di hello World - lezione 5&lt;/a&gt;&lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/815.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2011/05/15/lezioni-di-ldquopescardquo-.net-in-c-parte-5.aspx</guid>
            <pubDate>Sun, 15 May 2011 09:28:55 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/815.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2011/05/15/lezioni-di-ldquopescardquo-.net-in-c-parte-5.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/815.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Lavorare con XML parte 1</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2010/10/31/lavorare-con-xml-parte-1.aspx</link>
            <description>&lt;p&gt;Dopo un mese dall’evento di Pordenone, riesco finalmente ad avere il tempo di iniziare una breve serie di post dedicati alla serializzazione delle entity. Inizierò con l’helper di serializzazione già discusso in passato, ma ora riveduto e corretto usando il framework 4.0.&lt;/p&gt;
&lt;p&gt;Per persistere su disco una classe C# (oVB) bisogna che questa classe sia creata con alcuni, semplici accorgimenti che la rendano Serializzabile. Serializzazione è una parola che è iniziata ad arrivare ai miei orecchi attorno al 2003, alle prime conferenze su .NET, è una parola derivata dall’inglese Serialization, non esiste sul Devoto Oli, il suo significato è persistere lo stato di un oggetto che si trova nella memoria di un programma in esecuzione in modo tale da poter rigenerare l’oggetto nello stesso stato rileggendo le informazioni salvate su un disco (o altro analogo supporto di memoria di massa.)&lt;/p&gt;
&lt;p&gt;Le classi Entity, sono delle classi che non hanno nulla di particolare se non il fatto che rappresentano dei dati strutturati, pertanto vengono considerate tali tutte le classi che compongono ad esempio un modello dati, semplice, usato con LinqToSql oppure con EntityFramework, pertanto sono quelle che con maggiore probabilità hanno la necessità di essere serializzate.&lt;/p&gt;
&lt;p&gt;In .NET, è possibile serializzare dati in 2 modalità, la serializzazione binaria e la serializzazione XML. Tutti i tipi di dati base di .NET sono serializzabili, pertanto, qualsiasi classe che contiene solo dati di questo tipo è serializzabile in modo diretto, senza particolari modifiche se non che è indispensabile che la classe implementi un costruttore senza parametri.&lt;/p&gt;
&lt;p&gt;Che cosa viene serializzato automaticamente da .NET di un oggetto? Tutte le property Pubbliche, perché le sole property pubbliche? perché si assume che le variabili private possano essere rigenerate senza necessità di essere serializzate. Ma è ovviamente possibile effettuare un Override della serializzazione automatica e serializzare ciò che si vuole e come si vuole. &lt;/p&gt;
&lt;p&gt;In questa serie di articoli esamineremo solo la serializzazione standard e tutto quello che si può pilotare in essa utilizzando poche semplici funzionalità a nostra disposizione. &lt;/p&gt;
&lt;h3&gt;La classe SerializeHelper&lt;/h3&gt;
&lt;p&gt;Questa classe fornisce tutti i servizi di serializzazione sia per oggetti semplici che per oggetti compositi (collezioni od oggetti contenenti tipi di dati non semplici). Utilizza  le classi del namespace System.Xml e System.Xml.Serialization. Vediamone quindi i vari metodi:&lt;/p&gt;
&lt;h4&gt; &lt;/h4&gt;
&lt;h4&gt; &lt;/h4&gt;
&lt;h4&gt;BuildReader&lt;/h4&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XmlTextReader BuildReader(&lt;span class="kwrd"&gt;string&lt;/span&gt; pXmlString)
        {
            NameTable nt = &lt;span class="kwrd"&gt;new&lt;/span&gt; NameTable();
            XmlNamespaceManager nsmgr = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlNamespaceManager(nt);
            nsmgr.AddNamespace(&lt;span class="str"&gt;"bk"&lt;/span&gt;, &lt;span class="str"&gt;"urn:sample"&lt;/span&gt;);

            XmlParserContext context = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlParserContext(&lt;span class="kwrd"&gt;null&lt;/span&gt;, nsmgr, &lt;span class="kwrd"&gt;null&lt;/span&gt;, XmlSpace.None);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextReader(pXmlString, XmlNodeType.Element, context));
        }&lt;/pre&gt;
&lt;p&gt;Questo primo metodo, come dice il suo nome, crea un &lt;strong&gt;XmlTextReader&lt;/strong&gt;, che con il corrispondente &lt;strong&gt;XmlTextWriter&lt;/strong&gt; sono gli stream di base per la lettura e scrittura di dati XML. Il metodo qui scritto, è stato disegnato per permetterci di trasformare una stringa (ad esempio un campo di un database) in uno stream Xml. Si occupa di generare un contesto “fittizio” per così dire, per poter creare l’XmlTextReader in grado di fornire i dati Xml anche se l’input è una semplice stringa, non uno stream dati vero e proprio.&lt;/p&gt;
&lt;h4&gt;DeserializeFromString&lt;/h4&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; DeserializeFromString(Type pTypeToDeserialize, &lt;span class="kwrd"&gt;string&lt;/span&gt; pXmlString)
        {
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (XmlReader xr = BuildReader(pXmlString))
            {
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToDeserialize);
                ret = serializer.Deserialize(xr);
                xr.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; DeserializeFromString(Type pTypeToDeserialize, &lt;br /&gt;               Type[] pExtraTypes, &lt;span class="kwrd"&gt;string&lt;/span&gt; pXmlString)
        {
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (XmlReader xr = BuildReader(pXmlString))
            {
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToDeserialize, pExtraTypes);
                ret = serializer.Deserialize(xr);
                xr.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }&lt;/pre&gt;
&lt;p&gt;Questi due metodi, costruiti l’uno per una classe contenente solo dati semplici, l’altro per una classe contenente tipi di dati complessi, utilizzano il metodo precedente per creare uno stream dati che poi viene passato alla classe XmlSerializer e permette di ottenere l’oggetto originalmente serializzato.&lt;/p&gt;
&lt;h4&gt;DeserializeFromFile&lt;/h4&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; DeserializeFromFile(Type pTypeToDeserialize, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPath)
        {
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (XmlTextReader reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextReader(pPath))
            {
                &lt;span class="rem"&gt;// Occorre un'istanza della classe XmlSerializer&lt;/span&gt;
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToDeserialize);
                &lt;span class="rem"&gt;// e questo é tutto ciò che serve per leggere i dati dal formato XML&lt;/span&gt;
                ret = serializer.Deserialize(reader);
                reader.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; DeserializeFromFile(Type pTypeToDeserialize, &lt;br /&gt;            Type[] pExtraTypes, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPath)
        {
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (XmlTextReader reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextReader(pPath))
            {
                &lt;span class="rem"&gt;// Occorre un'istanza della classe XmlSerializer&lt;/span&gt;
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToDeserialize, pExtraTypes);
                &lt;span class="rem"&gt;// e questo é tutto ciò che serve per leggere i dati dal formato XML&lt;/span&gt;
                ret = serializer.Deserialize(reader);
                reader.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }&lt;/pre&gt;
&lt;p&gt;La deserializzazione da file è più semplice in quanto l’XmlTextreader può essere direttamente istanziato a partire dal nome di un file. I due overload di questo metodo permettono di specificare al deserializzatore quali sono le classi coinvolte, nel caso di oggetti non semplici. Vedremo il loro uso quando deserializzeremo le collection, ma allo stesso modo sono utili per la deserializzazione di oggetti complessi, che formano modelli con relazioni.&lt;/p&gt;
&lt;h4&gt;SerializeToFile&lt;/h4&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SerializeToFile(&lt;span class="kwrd"&gt;string&lt;/span&gt; pPath, &lt;span class="kwrd"&gt;object&lt;/span&gt; pObjToSerialize, &lt;br /&gt;          Type pTypeToSerialize, &lt;span class="kwrd"&gt;bool&lt;/span&gt; pNoNamespaces, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPrefix)
        {
            FileInfo fInfo = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileInfo(pPath);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Directory.Exists(fInfo.DirectoryName))
            {
                Directory.CreateDirectory(fInfo.DirectoryName);
            }            
            &lt;span class="kwrd"&gt;using&lt;/span&gt;(XmlTextWriter writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextWriter(pPath, Encoding.UTF8))
            {
                &lt;span class="rem"&gt;// write a readable file&lt;/span&gt;
                writer.Formatting = Formatting.Indented;
                writer.Indentation = 4;

                &lt;span class="rem"&gt;// Occorre un'istanza della classe XmlSerializer&lt;/span&gt;
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToSerialize);
                XmlSerializerNamespaces ns = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializerNamespaces();
                &lt;span class="kwrd"&gt;string&lt;/span&gt; prefix = pPrefix != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? pPrefix : &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (pNoNamespaces)
                {
                    ns.Add(prefix, TXT_Namespace);
                }
                &lt;span class="rem"&gt;// e questo é tutto ciò che serve per persistere i dati&lt;/span&gt;
                serializer.Serialize(writer, pObjToSerialize, ns);
                writer.Close();
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SerializeToFile(&lt;span class="kwrd"&gt;string&lt;/span&gt; pPath, &lt;span class="kwrd"&gt;object&lt;/span&gt; pObjToSerialize, 
            Type pTypeToSerialize, Type[] pExtraTypes, &lt;span class="kwrd"&gt;bool&lt;/span&gt; pNoNamespaces, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPrefix)
        {
            FileInfo fInfo = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileInfo(pPath);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Directory.Exists(fInfo.DirectoryName))
            {
                Directory.CreateDirectory(fInfo.DirectoryName);
            }            
            &lt;span class="kwrd"&gt;using&lt;/span&gt;(XmlTextWriter writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextWriter(pPath, Encoding.UTF8))
            {
                &lt;span class="rem"&gt;// write a readable file&lt;/span&gt;
                writer.Formatting = Formatting.Indented;
                writer.Indentation = 4;
                &lt;span class="rem"&gt;//writer.Settings.OutputMethod = XmlOutputMethod.&lt;/span&gt;
                &lt;span class="rem"&gt;// Occorre un'istanza della classe XmlSerializer&lt;/span&gt;
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pTypeToSerialize, pExtraTypes);
                XmlSerializerNamespaces ns = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializerNamespaces();
                &lt;span class="kwrd"&gt;string&lt;/span&gt; prefix = pPrefix != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? pPrefix : &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (pNoNamespaces)
                {
                    ns.Add(prefix, TXT_Namespace);
                }
                &lt;span class="rem"&gt;// e questo é tutto ciò che serve per persistere i dati&lt;/span&gt;
                serializer.Serialize(writer, pObjToSerialize, ns);
                writer.Close();
            }
        }&lt;/pre&gt;
&lt;p&gt;Per la serializzazione, oltre ai due overload che ci danno modo di dare informazioni al serializzatore sulle classi coinvolte, abbiamo aggiunto alcuni parametri che servono per la formattazione: pNoNamespaces e pPrefix. &lt;br /&gt;
Innanzi tutto possiamo notare come Creando l’XmlTextWriter, la classe che effettua la serializzazione, possiamo decidere l’encoding della stringa, pertanto, in base alle nostre esigenze possiamo cambiare l’encoding del file generato. Possiamo inoltre controllare la formattazione del file Xml generato usando l’opzione Formatting che ci da modo di indicare come deve essere formattato il testo, alcune altre property permettono di decidere l’ampiezza dell’indentazione e il carattere da utilizzare.&lt;/p&gt;
&lt;p&gt;l’uso di XmlSerializerNamespaces ci permette di evitare la verbosa serie dei namespaces inseriti all’apertura della serializzazione della classe:&lt;/p&gt;
&lt;p&gt;&amp;lt;Serializzabile xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema-instance"&lt;/a&gt; xmlns:xsd="&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema"&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p&gt;Sostituendola con:&lt;/p&gt;
&lt;p&gt;&amp;lt;Competences xmlns="&lt;a href="http://www.dotnetwork.it&amp;quot;"&gt;http://www.dotnetwork.it"&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p&gt;Oppure, usando il flag pNoNamespaces in:&lt;/p&gt;
&lt;p&gt;&amp;lt;Competences&amp;gt;&lt;/p&gt;
&lt;p&gt;Questo flag è opportuno utilizzarlo per creare classi neutre da utilizzare per lo scambio dati fra applicazioni di aziende diverse, mentre se vogliamo fare in modo che le nostre classi siano  marcate in modo specifico, lasciamo invece il namespace che abbiamo scelto per la nostra azienda, in modo tale che sia necessario specificamente implementarlo nelle classi da noi prodotte in modo tale da renderle univoche rispetto a quelle prodotte da altri.&lt;/p&gt;
&lt;p&gt;Il parametro pPrefix ha invece lo scopo di assegnare un prefisso agli elementi delle nostre classi.&lt;/p&gt;
&lt;p&gt;&amp;lt;dnw:Programmer xmlns:dnw="&lt;a href="http://www.dotnetwork.it"&gt;http://www.dotnetwork.it"&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;dnw:Skills&amp;gt;&lt;/p&gt;
&lt;p&gt;In questo modo possiamo specificare esattamente l’uso dei nostri oggetti senza dover reinserire il namespace completo.&lt;/p&gt;
&lt;h4&gt;SerializeToString&lt;/h4&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SerializeToString(&lt;span class="kwrd"&gt;object&lt;/span&gt; pObjToSerialize, &lt;br /&gt;            Type[] pExtraTypes, &lt;span class="kwrd"&gt;bool&lt;/span&gt; pNoNamespaces, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPrefix)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; ret = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (MemoryStream stream = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream())
            {
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pObjToSerialize.GetType(), pExtraTypes);
                XmlSerializerNamespaces ns = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializerNamespaces();
                &lt;span class="kwrd"&gt;string&lt;/span&gt; prefix = pPrefix != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? pPrefix : &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (pNoNamespaces)
                {
                    ns.Add(prefix, TXT_Namespace);
                }
                serializer.Serialize(stream, pObjToSerialize, ns);
                ret = Encoding.UTF8.GetString(stream.ToArray());
                stream.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SerializeToString(&lt;span class="kwrd"&gt;object&lt;/span&gt; pObjToSerialize, &lt;span class="kwrd"&gt;bool&lt;/span&gt; pNoNamespaces, &lt;span class="kwrd"&gt;string&lt;/span&gt; pPrefix)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; ret = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (MemoryStream stream = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream())
            {
                XmlSerializer serializer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(pObjToSerialize.GetType());
                XmlSerializerNamespaces ns = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializerNamespaces();
                &lt;span class="kwrd"&gt;string&lt;/span&gt; prefix = pPrefix != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? pPrefix : &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (pNoNamespaces)
                {
                    ns.Add(prefix, TXT_Namespace);
                }
                serializer.Serialize(stream, pObjToSerialize, ns);
                ret = Encoding.UTF8.GetString(stream.ToArray());
                stream.Close();
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }&lt;/pre&gt;
&lt;p&gt;L’ultimo metodo, sempre con due overload, permette la serializzazione di un oggetto in Xml su una stringa, per poterlo fare dobbiamo utilizzare uno Stream, visto che dobbiamo poi trasformarlo in una stringa, utilizziamo un Memory Stream, per non dover generare un file. La procedura per la generazione dell’Xml, è identica a quella per i files.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:34aabb1a-0e90-48b7-8fd8-a98914f96dc4" class="wlWriterEditableSmartContent"&gt;Technorati Tag: &lt;a href="http://technorati.com/tags/C%23" rel="tag"&gt;C#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Xml" rel="tag"&gt;Xml&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Serializzazione" rel="tag"&gt;Serializzazione&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Helper" rel="tag"&gt;Helper&lt;/a&gt;&lt;/div&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/539.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2010/10/31/lavorare-con-xml-parte-1.aspx</guid>
            <pubDate>Sun, 31 Oct 2010 22:02:06 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/539.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2010/10/31/lavorare-con-xml-parte-1.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/539.aspx</wfw:commentRss>
        </item>
        <item>
            <title>This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2010/06/18/this-assembly-is-built-by-a-runtime-newer-than-the.aspx</link>
            <description>&lt;p&gt;Scusate lo strano titolo del post, ma probabilmente chi incontrerà questo errore proverà a cercarlo su un motore di ricerca e me ne sarà grato.&lt;/p&gt;
&lt;p&gt;Premessa: I miei programmi, quando installati sui PC degli utenti finali per principio Non usano la GAC a meno che io non vi sia obbligata per poter esporre una qualche funzionalità a .COM.&lt;/p&gt;
&lt;p&gt;Però, per la struttura con cui sono costruite le molte ed articolate librerie di base utilizzate per i miei progetti, tali librerie di base sulle macchine di sviluppo (e solo sulle macchine di sviluppo) vengono pubblicate in GAC. Questo serve a permettere a noi programmatori di poter aggiornare una libreria di base ed essere certi che qualsiasi soluzione/progetto che usa questa libreria base istantaneamente abbia le modifiche disponibili.&lt;/p&gt;
&lt;p&gt;Per quale motivo facciamo tutto questo, perché le DLL poste in GAC non vengono copiate sulla cartella locale di ogni progetto che le usa da Visual Studio e quindi, ricompilando il progetto che referenzia la DLL base, esso fa certamente riferimento alla DLL giusta.&lt;/p&gt;
&lt;p&gt;Questa soluzione è stata adottata dopo che il setup di una applicazione, a causa dell’ordine in cui il progetto di setup ha copiato le DLL referenziate quando è stato generato, ha inserito una versione vecchia di una dll e quindi l’aggiornamento installato dal cliente non funzionava.&lt;/p&gt;
&lt;p&gt;Detto questo, che roba è il titolo di questo post?&lt;/p&gt;
&lt;p&gt;Il titolo di questo post è il messaggio di errore che gacutil.exe, l’utility che installa e disinstalla dalla GAC gli assembly produce tentando di caricare in GAC una DLL compilata con il framework 4.0. Il gacutil.exe che uso io, me lo porto dietro dal 2005, infatti tale utility si trova sperduta nei meandri dell’SDK di Windows quindi, opportunamente, io ne ho fatto copia e la metto su C:\Windows così sono sicura di trovarla (Lo so che per qualche sistemista sarà un eresia, ma ragazzi, noi programmatori dobbiamo lavorà!)&lt;/p&gt;
&lt;p&gt;Detto ciò, la mia utility scritta per il framework 2.0 funziona correttamente fino al framework 3.5 poi non funziona più e da questo messaggio.&lt;/p&gt;
&lt;p&gt;Il motivo per cui non funziona più non lo so esattamente ma, con il framework 4.0 la GAC non si trova più dove era prima, ovvero:&lt;/p&gt;
&lt;p&gt;c:\Windows\Assembly&lt;/p&gt;
&lt;p&gt;ma è stata spostata (per ragioni più che giustificate ovviamente) e si trova sotto: &lt;/p&gt;
&lt;p&gt;C:\Windows\Microsoft.NET\assembly\GAC_MSIL (per lo meno sul mio pc con windows Vista business)&lt;/p&gt;
&lt;p&gt;pertanto, è necessario procurarsi ed usare il nuovo gacutil.exe fornito con Visual Studio 2010 accessibile senza tema usando il prompt dei comandi di Visual Studio, ma nascosto e praticamente introvabile a chi non conosca per filo e per segno le cartelle degli SDK di Microsoft.&lt;/p&gt;
&lt;p&gt;Sulla mia macchina, il nuovo gacutil.exe si trova qui:&lt;/p&gt;
&lt;p&gt;C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools&lt;/p&gt;
&lt;p&gt;Sostituito questo con l’originale la registrazione va a buon fine e gli assembly vengono copiati sulla GAC correttamente, e ovviamente vengono correttamente registrati anche gli assembly delle versioni precedenti del framework.&lt;/p&gt;
&lt;div style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0b541a59-5c49-4ee5-ae77-f1f95e53fb1d" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/GAC/default.aspx"&gt;GAC&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/gacutil/default.aspx"&gt;gacutil&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/VS2010/default.aspx"&gt;VS2010&lt;/a&gt;&lt;/div&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/439.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2010/06/18/this-assembly-is-built-by-a-runtime-newer-than-the.aspx</guid>
            <pubDate>Fri, 18 Jun 2010 12:56:24 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/439.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2010/06/18/this-assembly-is-built-by-a-runtime-newer-than-the.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/439.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Disattivare il caricamento automatico dei Controlli in Toolbox</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2009/03/30/disattivare-il-caricamento-automatico-dei-controlli-in-toolbox.aspx</link>
            <description>&lt;p&gt;Se come me avete delle soluzioni che creano un certo numero di Components (da 30 a 200), la funzionalità per cui Visual Studio aggiunge automaticamente questi Tools alla Toolbox ad ogni ricompilazione, apertura della soluzione, modifica o aggiunta di una nuova classe, può risultare noiosa, prima di tutto perché durante questa operazione non ci sono cursori di attesa e sembra che Visual Studio sia Piantato, secondariamente perché difficilmente andrete a trascinare componenti in una soluzione di soli componenti se non per fare dei test, ma in questo caso credo siate sufficientemente cresciuti da poter scrivere una riga di codice a mano per creare il componente. Per togliere il fastidio basta eseguire la seguente modifica alle opzioni di Visual Studio: Tools &amp;gt; Options &amp;gt; Windows Forms Designer &amp;gt; ToolBox &amp;gt; AutoToolboxPopulate = false Al contrario, se per qualsiasi motivo questa funzione non vi venisse eseguita automaticamente e a voi serve, controllate che questo flag sia posto a True. Ricordo che le classi prese in considerazione da questa funzione sono quelle derivate da Control e Component. &lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/VisualStudio/default.aspx"&gt;VisualStudio&lt;/a&gt; &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/Toolbox/default.aspx"&gt;Toolbox&lt;/a&gt; &lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/165.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2009/03/30/disattivare-il-caricamento-automatico-dei-controlli-in-toolbox.aspx</guid>
            <pubDate>Mon, 30 Mar 2009 08:22:31 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/165.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2009/03/30/disattivare-il-caricamento-automatico-dei-controlli-in-toolbox.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/165.aspx</wfw:commentRss>
        </item>
        <item>
            <title>SQL Server Come impostare una Query che ritorna sempre almeno una riga.</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2008/04/12/sql-server-come-impostare-una-query-che-ritorna-sempre-almeno.aspx</link>
            <description>&lt;p&gt;Faccio un Post per interposta persona, infatti questa soluzione arriva dal mio nuovo collega, Luca Del Mestre che spero di convincere presto a scrivere personalmente su DotNetWork.&lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Spesso ci troviamo ad avere la necessità di leggere da Database un singolo record di una tabella, a volte contiene dei parametri da usare nell'applicazione, a volte contiene il dettaglio di un particolare dato, è comunque comune alle applicazioni che lavorano con i DB.&lt;/p&gt;
&lt;p&gt;Se la query che ci aspettiamo ritornare una riga non torna nulla, spesso, il codice necessario a gestire questo tipo di accadimento è lungo e decisamente poco utile, farebbe invece comodo e ci permetterebbe di risparmiare parecchio codice e parecchi grattacapi se la query ritornasse una riga in ogni caso, solamente facendo in modo che una riga non valida sia vuota.&lt;/p&gt;
&lt;p&gt;Luca, che è un DBA Oracle, mi ha mostrato come in Oracle vi sia una sintassi nel dialetto SQL che permette di ottenere questo tipo di funzionalità, SQL Server ne ha una corrispondente però, in SQL 2005 applicandola si riceve un messaggio di errore che la indica come parte di SQL 2000 da non usarsi se non modificando il livello di compatibilità del db alla versione 2000. Ma ovviamente c'è sempre un metodo alternativo per risolvere il problema.&lt;/p&gt;
&lt;p&gt;L'esempio che vi posto è creato su una ipotetica tabella Users che mappa gli utenti Windows che hanno accesso ad una applicazione su database.&lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;strong&gt;La tabella:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;pre class="TsqlFormat"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; [paperinik]
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; [dbo].[TbUsers](
    [IDUser] [uniqueidentifier] &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [WinUser] [nvarchar](128) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [WinDomain] [nvarchar](128) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [UserName] [nvarchar](255) &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DataLogin] [datetime] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [IDAzienda] [&lt;span class="kwrd"&gt;nchar&lt;/span&gt;](3) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [InternalMail] [nvarchar](128) &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [Obsoleto] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [ObsoletoDal] [datetime] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [IsAdmin] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [IsSupervisor] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [DirectConnection] [&lt;span class="kwrd"&gt;bit&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
    [LastUpdated] [&lt;span class="kwrd"&gt;timestamp&lt;/span&gt;] &lt;span class="kwrd"&gt;NULL&lt;/span&gt;,
         &lt;span class="kwrd"&gt;CONSTRAINT&lt;/span&gt; [PK_TbMcpUsers] &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; &lt;span class="kwrd"&gt;NONCLUSTERED&lt;/span&gt; 
        (
            [IDMcpUser] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;
        ) &lt;span class="kwrd"&gt;ON&lt;/span&gt; [&lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt;]
    ) &lt;span class="kwrd"&gt;ON&lt;/span&gt; [&lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt;]&lt;/pre&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;strong&gt;La classe di test:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; User
    {

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SQL_CnString = &lt;span class="str"&gt;"integrated security = SSPI; data source = .; initial catalog = paperinik;"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FLD_IDUser = &lt;span class="str"&gt;"IDUser"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FLD_WinUser = &lt;span class="str"&gt;"WinUser"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FLD_WinDomain = &lt;span class="str"&gt;"WinDomain"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FLD_UserName = &lt;span class="str"&gt;"UserName"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FLD_IsAdmin = &lt;span class="str"&gt;"IsAdmin"&lt;/span&gt;;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SQL_ValidateUser = &lt;span class="str"&gt;@"
            SELECT [IDUser]
                  ,[WinUser]
                  ,[WinDomain]
                  ,[UserName]
                  ,[DataLogin]
                  ,[IDAzienda]
                  ,[InternalMail]
                  ,[Obsoleto]
                  ,[ObsoletoDal]
                  ,[IsAdmin]
                  ,[IsSupervisor]
                  ,[DirectConnection]
                  ,[LastUpdated]
                FROM TbUsers usr
                RIGHT OUTER JOIN (SELECT @WinUser ut, @WinDomain do) fake
                        ON (usr.WinUser = fake.ut AND usr.WinDomain = fake.do)
        "&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TXT_UtenteNonValido = &lt;span class="str"&gt;"Utente non valido"&lt;/span&gt;;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mClassName = System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; DataRow mUserRow;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Guid IDUser
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (mUserRow[FLD_IDUser] == System.DBNull.Value)
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; Guid.Empty;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; (Guid)mUserRow[FLD_IDUser];
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; WinUser
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (mUserRow[FLD_WinUser] == System.DBNull.Value)
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;)mUserRow[FLD_WinUser];
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; WinDomain
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (mUserRow[FLD_WinDomain] == System.DBNull.Value)
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;)mUserRow[FLD_WinDomain];
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserName
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (mUserRow[FLD_UserName] == System.DBNull.Value)
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; TXT_UtenteNonValido;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;)mUserRow[FLD_UserName];
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsAdmin
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (mUserRow[FLD_IsAdmin] == System.DBNull.Value)
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;bool&lt;/span&gt;)mUserRow[FLD_IsAdmin];
                }
            }
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsValid()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt;( UserName != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; UserName != TXT_UtenteNonValido);
        }


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ValidateUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; pWinUser, &lt;span class="kwrd"&gt;string&lt;/span&gt; pWinDomain)
        {
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection cn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection())
            {
                SqlParameter[] sqlParam = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter[] {
                    &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter( &lt;span class="str"&gt;"@WinUser"&lt;/span&gt;, pWinUser ),
                    &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter( &lt;span class="str"&gt;"@WinDomain"&lt;/span&gt;, pWinDomain )
                };
                cn.ConnectionString = SQL_CnString;
                cn.Open();
                SqlCommand cmd = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand();
                cmd.Connection = cn;
                cmd.CommandText = SQL_ValidateUser;
                cmd.Parameters.AddRange(sqlParam);
                SqlDataReader dr = cmd.ExecuteReader();
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (dr.HasRows)
                {
                    DataTable dt = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();
                    dt.Load(dr);
                    mUserRow = dt.Rows[0];
                }
                cn.Close();
            }
        }

    }&lt;/pre&gt;
&lt;p&gt;Che cosa otteniamo provando ad usare la classe in una applicazione Windows dove io ho inserito un record per il signor M.Rossi e invece non ho inserito il signor G.Rossi?:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/SQLServerComeimpostareunaQuerycheritorn_DD1E/sc_blog_sqlsempreriga01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="271" alt="sc_blog_sqlsempreriga01" width="486" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/SQLServerComeimpostareunaQuerycheritorn_DD1E/sc_blog_sqlsempreriga01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Il signor G.Rossi non è un utente mappato.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/SQLServerComeimpostareunaQuerycheritorn_DD1E/sc_blog_sqlsempreriga02_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="271" alt="sc_blog_sqlsempreriga02" width="486" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/SQLServerComeimpostareunaQuerycheritorn_DD1E/sc_blog_sqlsempreriga02_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Il signor M.Rossi invece è mappato sulla tabella.&lt;/p&gt;
&lt;p&gt;Dov'è il trucco per far si che la query che potete notare all'inizio della classe di test ritorni sempre un record:&lt;/p&gt;
&lt;pre class="TsqlFormat"&gt;            &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [IDUser]
                  ,[WinUser]
                  ,[WinDomain]
                  ,[UserName]
                  ,[DataLogin]
                  ,[IDAzienda]
                  ,[InternalMail]
                  ,[Obsoleto]
                  ,[ObsoletoDal]
                  ,[IsAdmin]
                  ,[IsSupervisor]
                  ,[DirectConnection]
                  ,[LastUpdated]
                &lt;span class="kwrd"&gt;FROM&lt;/span&gt; TbUsers usr
                &lt;span class="kwrd"&gt;RIGHT&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @WinUser ut, @WinDomain do) fake
                        &lt;span class="kwrd"&gt;ON&lt;/span&gt; (usr.WinUser = fake.ut &lt;span class="kwrd"&gt;AND&lt;/span&gt; usr.WinDomain = fake.do)&lt;/pre&gt;
&lt;p&gt;Il segreto è la &lt;strong&gt;RIGHT OUTER JOIN&lt;/strong&gt; utilizzata per costruire un filtro furbo, ove invece di fare una semplice&lt;/p&gt;
&lt;pre class="TsqlFormat"&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;
    WinUser = @WinUser &lt;span class="kwrd"&gt;AND&lt;/span&gt; WinDomain = @WinDomain&lt;/pre&gt;
&lt;p&gt;Usiamo i 2 parametri del filtro per costruire una tabella al volo che chiamiamo fake (falsa)&lt;/p&gt;
&lt;pre class="TsqlFormat"&gt;(&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; @WinUser ut, @WinDomain do) fake&lt;/pre&gt;
&lt;p&gt;E facciamo una &lt;strong&gt;RIGHT JOIN&lt;/strong&gt; fra questa tabella e la tabella utenti utilizzando la clausola &lt;strong&gt;OUTER&lt;/strong&gt; per cui per ogni riga della tabella posta a destra della JOIN viene creata una riga nella tabella risultante, che, quando non vi fossero valori nella tabella LEFT (la nostra USER) riempie i campi con NULL.&lt;/p&gt;
&lt;p&gt;In questo modo, otteniamo un record valido per M.Rossi e un record vuoto per G.Rossi. Come possiamo notare, la nostra classe di test mappa direttamente i campi della DataRow sulle property con la sola gestione del DBNull, senza questa soluzione, per ottenere una classe funzionante, avremmo dovuto mappare i campi su variabili a livello di classe e fare una funzione di Clear che le svuota quando non c'è una riga che possa aggiornare i dati. Avremmo inoltre dovuto aggiornare le variabili a livello di classe dalla DataRow aggiungendo codice ulteriore e OverHead al nostro sistema.&lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/SQL/default.aspx"&gt;SQL&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/Query/default.aspx"&gt;Query&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/CheckIdent/default.aspx"&gt;CheckIdent&lt;/a&gt;,&lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/SqlServer/default.aspx"&gt;SqlServer&lt;/a&gt;&lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/75.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2008/04/12/sql-server-come-impostare-una-query-che-ritorna-sempre-almeno.aspx</guid>
            <pubDate>Sat, 12 Apr 2008 14:07:49 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/75.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2008/04/12/sql-server-come-impostare-una-query-che-ritorna-sempre-almeno.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/75.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Due parole su GetHashCode e sugli operatori di Uguaglianza (Storico)</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2008/03/24/due-parole-su-gethashcode-e-sugli-operatori-di-uguaglianza-storico.aspx</link>
            <description>&lt;p&gt;&lt;font size="4"&gt;&lt;strong&gt;A che cosa serve GetHashCode?&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Domanda che mi è sovvenuta perché dovendo predisporre per una serie di classi un Override dell'operatore == in modo da poterle comparare semplicemente, il sistema mi obbliga (per poter compilare) a fare l'override anche di due metodi della classe che sono:&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;Equals()

GetHashCode()
&lt;/pre&gt;
&lt;p&gt;Se il primo è, almeno dal nome, semplice da capire il secondo no, pertanto sono andata a cercare di cosa si tratta e come è opportuno farne l'override per mantenerlo corretto. Questa è la traduzione della risposta che ho trovato più coerente: &lt;/p&gt;
&lt;p&gt;A cosa serve GetHashCode? &lt;/p&gt;
&lt;p&gt;Viene utilizzato per determinare se due oggetti sono identici. Viene utilizzato da Equals nella sua forma standard per determinare se due oggetti sono lo stesso oggetto. Questo è vero se tutti gli attributi della classe sono uguali. &lt;/p&gt;
&lt;p&gt;Se si vuole creade le tue strutture o classi e compararle utilizzando Equals, devi costruire il tuo valore di Hash. Il modo più semplice per farlo è fare un or esclusivo tra i valori di Hash degli attributi che identificano il tuo oggetto e ritornare quel valore. Se si effettua l'Override di Equals è necessario fare l'override di GetHashCode(). &lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;strong&gt;Operatori di Uguaglianza, e disuguaglianza&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Faccio seguito al post precedente, perché mi sono spinta un po' più a fondo sull'argomento e seguendo alcune indicazioni fornite dalle specifiche di base di .NET e dalle best practices che chi ne sa più di me ha fornito sono arrivata a qualcosa di un po' più articolato, ovvero, se volete generare una classe di tipo &lt;em&gt;Entity&lt;/em&gt; (che rappresenta quindi un Dato di qualche genere) e volete che questo oggetto supporti la possibilità di essere inserito in una &lt;em&gt;collection&lt;/em&gt;, di essere &lt;em&gt;ricercato&lt;/em&gt;, &lt;em&gt;ordinato&lt;/em&gt;, &lt;em&gt;comparato&lt;/em&gt; in  modo standard, è necessario procedere nel seguente modo: &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Implementare il vostro oggetto in forma base, quindi definirne i &lt;strong&gt;campi&lt;/strong&gt;, le &lt;strong&gt;proprietà&lt;/strong&gt; e la funzione base &lt;strong&gt;ToString&lt;/strong&gt; (perché quella dell'object è un po' misera). &lt;/li&gt;
    &lt;li&gt;Se volete rendere l'oggetto &lt;strong&gt;serializzabile&lt;/strong&gt;, quindi usabile via WebServices oppure semplicemente scrivibile/leggibile su disco, generare le funzioni &lt;strong&gt;ReadXml&lt;/strong&gt; e &lt;strong&gt;WriteXml&lt;/strong&gt; &lt;/li&gt;
    &lt;li&gt;Implementare l'interfaccia &lt;strong&gt;IComparable&lt;/strong&gt;, che si compone di un'unico metodo &lt;strong&gt;CompareTo &lt;/strong&gt;che ci permette di stabilire un metodo univoco per definire se due dei nostri oggetti sono uguali, maggiori, minori l'uno all'altro. &lt;/li&gt;
    &lt;li&gt;Implementare l'operatore di Uguaglianza (&lt;strong&gt;==&lt;/strong&gt;) e obbligatoriamente quello di disuguaglianza (&lt;strong&gt;!=&lt;/strong&gt;) e di conseguenza su richiesta del compilatore implementare l'override dei metodi &lt;strong&gt;Equals&lt;/strong&gt; e &lt;strong&gt;GetHashCode&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Una cosa a cui fare molta attenzione è la seguente, le specifiche base di .NET dicono che la funzione &lt;strong&gt;Equals&lt;/strong&gt; deve ritornare &lt;em&gt;true&lt;/em&gt; solo se 2 oggetti sono lo stesso oggetto, mentre l'operatore di uguaglianza (==)può coincidere con Equals oppure fornire una uguaglianza in base ai contenuti. E qui, voi, come me direte "Omioddio ma come è possibile..." è molto semplice, anche se un pochino contorto, facciamo un esempio:&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;DateTime DataUno = &lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime( 2006, 05, 21);
DateTime DataDue = &lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime( 2006, 05, 21);

&lt;span class="kwrd"&gt;bool&lt;/span&gt;  compareValue = DataUno == DataDue;

&lt;span class="kwrd"&gt;bool&lt;/span&gt; equalValue = DataUno.Equals(DataDue);
&lt;/pre&gt;
&lt;p&gt;In questo caso, compareValue è true, mentre equalValue è false&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;DateTime DataUno = &lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime( 2006, 05, 21);
DateTime DataDue = DataUno

&lt;span class="kwrd"&gt;bool&lt;/span&gt;  compareValue = DataUno == DataDue;

&lt;span class="kwrd"&gt;bool&lt;/span&gt; equalValue = DataUno.Equals(DataDue);
&lt;/pre&gt;
&lt;p&gt;In questo caso, invece, entrambi i valori di comparazione sono true. &lt;/p&gt;
&lt;p&gt;C'è un solo piccolo problema che ogni tanto sono certa ha introdotto bacherozzi in più di una applicazione, se utilizzo la seconda versione, dato che &lt;em&gt;DataUno&lt;/em&gt; e &lt;em&gt;DataDue&lt;/em&gt; sono lo stesso oggetto, se cambio il contenuto di &lt;em&gt;DataUno&lt;/em&gt; ho cambiato di conseguenza anche &lt;em&gt;DataDue&lt;/em&gt;, mentre se utilizzo la prima versione, se cambio &lt;em&gt;DataUno&lt;/em&gt;, &lt;em&gt;DataDue&lt;/em&gt; rimane quella di prima. &lt;/p&gt;
&lt;p&gt;A cosa è dovuto tutto questo? Al fatto che mentre &lt;strong&gt;Equals&lt;/strong&gt; si basa sull'uguaglianza fra gli &lt;strong&gt;HashCode&lt;/strong&gt; degli oggetti, &lt;strong&gt;==&lt;/strong&gt;  si basa sulla comparazione dei contenuti. Faccio un esempio pratico così vediamo come realizzare una classe &lt;strong&gt;Entity&lt;/strong&gt; che rispetti le specifiche, cioè si comporti come la nostra classe del Framework standard &lt;strong&gt;DateTime&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;La classe esempio è naturalmente una classe inutile per il 99% di coloro che leggeranno l'articolo, infatti costruisce un Entity che permette di definire una coppia di colori Console per cambiare colore al testo di una Write o Writeline su una finestra console. Però questa classe è serializzabile, comparabile e sortabile secondo direttive standard. &lt;/p&gt;
&lt;p&gt;Per permettere un copia incolla utile in visual studio, ve la scrivo tutta, ma commenterò i pezzi che ci interessano scrivendo in Rosso &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;&lt;span class="preproc"&gt;#region&lt;/span&gt; Using directives

&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml.Serialization;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ForYou.Base;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ForYou.Base.Xml;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.ComponentModel;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ForYou.Base.Exceptions;

&lt;span class="preproc"&gt;#endregion&lt;/span&gt;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; ForYou.UI.TheConsole.Data.Entities
{
    &lt;span class="rem"&gt;///&lt;/span&gt;
    &lt;span class="rem"&gt;/// Descrizione della classe: &lt;/span&gt;
    &lt;span class="rem"&gt;///&lt;/span&gt;
    &lt;span class="rem"&gt;///&lt;/span&gt;
    &lt;span class="rem"&gt;///&lt;/span&gt;
    [Serializable, XmlRoot(Namespace = &lt;span class="str"&gt;&lt;a href="http://www.visual-basic.it"&gt;http://www.visual-basic.it&lt;/a&gt;&lt;/span&gt;)] &lt;br /&gt;&lt;span class="rem"&gt;	//Attributo che indica che la classe è serializzabile e il &lt;br /&gt;		namespace univoco per le nostre Entity&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ConsoleItemColor : INotifyPropertyChanged, IComparable
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; Variabili &lt;span class="kwrd"&gt;private&lt;/span&gt;

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Nome della classe usato per debug nella generazione delle eccezioni&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mClassName = &lt;br /&gt;	System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mClassNameS = &lt;br /&gt;	System.Reflection.MethodBase.GetCurrentMethod().ReflectedType.Name;

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore del testo&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ConsoleColor mTextColor;

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore dello schermo&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ConsoleColor mScreenColor;
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Events

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Evento che si scatena alla modifica di una delle proprietà&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; PropertyChangedEventHandler PropertyChanged;
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Costruttore

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Costruttore&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore del testo&lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore dello schermo&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ConsoleItemColor( ConsoleColor pTextColor,&lt;br /&gt;	 ConsoleColor pScreenColor)
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mTextColor = pTextColor;
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mScreenColor = pScreenColor;
        }

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Costruttore&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// V.1.0&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ConsoleItemColor()
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mScreenColor = ConsoleColor.Black;
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mTextColor = ConsoleColor.White;
        }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Una piccola nota sul costruttore privato&lt;/strong&gt;: questo oggetto deve per forza avere i 2 valori dei colori definiti nel costruttore, però, per essere serializzabile, un oggetto deve implementare un costruttore senza parametri, per evitare che chi usa l'oggetto abbia accesso al costruttore senza parametri, mentre la funzione di Serializzazione e Deserializzazione invece possano utilizzarlo, lo definiamo &lt;strong&gt;private&lt;/strong&gt;. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Proprietà

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore del testo&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ConsoleColor TextColor
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; mTextColor;
            }
            set
            {
                mTextColor = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
                OnPropertyChanged(&lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"TextColor"&lt;/span&gt;));
            }
        }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Una nota sull'implementazione di INotifyPropertyChange&lt;/strong&gt;: è un interfaccia molto utile ed interessante da implementare sugli oggetti Entity per permettere di reagire alla modifica di una property in modo automatico implementando un Event Handler sull'evento Property Changed (ad esempio sulla User interface - ovviamente la console non è il massimo, però...). &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Colore dello schermo&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ConsoleColor ScreenColor
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; mScreenColor;
            }
            set
            {
                mScreenColor = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
                OnPropertyChanged(&lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"ScreenColor"&lt;/span&gt;));
            }
        }

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Restituisce il console Item Color corrente con i colori invertiti&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ConsoleItemColor ReverseColor
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ConsoleItemColor( &lt;span class="kwrd"&gt;this&lt;/span&gt;.mScreenColor,&lt;span class="kwrd"&gt;this&lt;/span&gt;.mTextColor);
            }
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Metodi pubblici

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Operatore di uguaglianza, 2 ConsoleItemColor sono &lt;br /&gt;		uguali se hanno gli stessi colori per testo e Schermo&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// ConsoleSize da confrontare&lt;/span&gt;
        &lt;span class="rem"&gt;/// ConsoleSize di confronto&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; ==(ConsoleItemColor pX, ConsoleItemColor pY)
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;bool&lt;/span&gt; ret = &lt;span class="kwrd"&gt;false&lt;/span&gt;;

                &lt;span class="kwrd"&gt;object&lt;/span&gt; oX = (&lt;span class="kwrd"&gt;object&lt;/span&gt;)pX;
                &lt;span class="kwrd"&gt;object&lt;/span&gt; oY = (&lt;span class="kwrd"&gt;object&lt;/span&gt;)pY;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (oX == &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; oY == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                {
                    ret = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (oX != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; oY != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (pX.CompareTo(pY) == 0)
                        {
                            ret = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                        } &lt;span class="rem"&gt;// if&lt;/span&gt;
                    }
                }
                &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassNameS + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name + &lt;span class="str"&gt;": "&lt;/span&gt; + ex.Message, ex);
            }
        }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Primo dei metodi per noi interessanti: Implementazione dell'operatore di uguaglianza (==) in questo caso, utilizziamo &lt;strong&gt;Object&lt;/strong&gt; come mezzo per testare e gestire correttamente la comparazione con il &lt;strong&gt;null &lt;/strong&gt;quindi trasformiamo gli operandi in Object per poter usare l'operatore di uguaglianza di base. Se non facessimo così, creeremmo una funzione ricorsiva, (provare per credere) e un bellissimo Stack Overflow.&lt;br /&gt;
Se gli operandi non sono nulli, l'uguaglianza esiste solo se la funzione &lt;strong&gt;CompareTo&lt;/strong&gt; implementazione di &lt;strong&gt;IComparable&lt;/strong&gt; ritorna &lt;strong&gt;0&lt;/strong&gt;. Per il CompareTo, scendete un po' più in basso. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Operatore di disuguaglianza, 2 &lt;br /&gt;		ConsoleItemColor sono diversi se non sono uguali&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// ConsoleSize da confrontare&lt;/span&gt;
        &lt;span class="rem"&gt;/// ConsoleSize di confronto&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; !=(ConsoleItemColor pX, ConsoleItemColor pY)
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; (!(pX == pY));
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassNameS + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name, ex);
            }

        }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Come possiamo notare, la disuguaglianza è solo una negazione dell'uguaglianza, pertanto la sua descrizione è corretta, due ConsoleItemColor sono diversi se non sono uguali... :o) &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Indica se 2 instanze di oggetti sono uguali&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Oggetto da comparare&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// true se obj e this sono lo stesso oggetto e hanno lo stesso valore&lt;/span&gt;
        &lt;span class="rem"&gt;/// false al contrario.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Equals(&lt;span class="kwrd"&gt;object&lt;/span&gt; obj)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; ret = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt;( obj == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
                {
                    ret = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (obj &lt;span class="kwrd"&gt;is&lt;/span&gt; ConsoleItemColor)
                    {
                        ret = &lt;span class="kwrd"&gt;this&lt;/span&gt;.GetHashCode() == obj.GetHashCode();
                    } &lt;span class="rem"&gt;// if&lt;/span&gt;
                } &lt;span class="rem"&gt;// else&lt;/span&gt;
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt;( ExceptionHelper.BaseExceptionTypeEquals(ex,&lt;br /&gt;		 &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(NullReferenceException) ))
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt;( obj == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
                    {
                        ret = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                    }
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassName + &lt;span class="str"&gt;"."&lt;/span&gt; 
                    + System.Reflection.MethodBase.GetCurrentMethod().Name, ex);    
                }
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt;( ret );
        }&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anche l'implementazione di &lt;strong&gt;Equals&lt;/strong&gt; è un po' più lunga di una semplice uguaglianza tra &lt;strong&gt;HashCode&lt;/strong&gt;, questo per riuscire a gestire correttamente gli oggetti &lt;strong&gt;null&lt;/strong&gt;, ovviamente se non volete gestire la nullabilità togliete tutto quello che ho scritto e lasciate che &lt;strong&gt;Equals&lt;/strong&gt; lanci una bella &lt;em&gt;NullReferenceException&lt;/em&gt; gestendone il risultato a monte. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Restituisce lo hash code dell'instanza dell'oggetto&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Un intero a 32-bit che contiene l'hash code dell'instanza dell'oggetto&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetHashCode()
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt;(&lt;span class="kwrd"&gt;base&lt;/span&gt;.GetHashCode());
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassName + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name, ex);
            }
        }&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Contrariamente a quanto indicato nel post precedente, che è una delle modalità per gestire gli Hash, ho scelto di implementare semplicemente la chiamata allo Hash della classe base (&lt;strong&gt;Object&lt;/strong&gt;) perché in questo modo sono certa che &lt;strong&gt;Equals&lt;/strong&gt; funziona come voglio io, ovvero ritorna &lt;strong&gt;True&lt;/strong&gt; solo se gli oggetti comparati sono lo &lt;em&gt;stesso&lt;/em&gt; oggetto. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Visualizza il contenuto della classe come una stringa&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToString()
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
                sb.AppendFormat(&lt;span class="str"&gt;"{0};{1}"&lt;/span&gt;, &lt;span class="kwrd"&gt;this&lt;/span&gt;.TextColor, &lt;span class="kwrd"&gt;this&lt;/span&gt;.ScreenColor);
                &lt;span class="kwrd"&gt;return&lt;/span&gt;(sb.ToString());
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassName + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name + &lt;span class="str"&gt;": "&lt;/span&gt; + ex.Message, ex);
            }
        }

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Serializza la classe su un file in formato XML&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///Path del file da generare&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteXml(&lt;span class="kwrd"&gt;string&lt;/span&gt; pXmlPath)
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                Stat.CheckEmptyPath(pXmlPath);
                ObjSerializer so = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjSerializer();
                so.SerializeToFile(pXmlPath, &lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ConsoleItemColor));
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + &lt;span class="kwrd"&gt;this&lt;/span&gt;.mClassName + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name + &lt;span class="str"&gt;" "&lt;/span&gt; + ex.Message, ex);
            }
        }

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Serializza la classe su una stringa&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Stringa XML contenente l'oggetto serializzato&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; WriteXml()
        {
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                ObjSerializer so = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjSerializer();
                &lt;span class="kwrd"&gt;return&lt;/span&gt; (so.SerializeToString(&lt;span class="kwrd"&gt;this&lt;/span&gt;));
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + &lt;span class="kwrd"&gt;this&lt;/span&gt;.mClassName + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name + &lt;span class="str"&gt;" "&lt;/span&gt; + ex.Message, ex);
            }
        }

        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Deserializza una classe da un file XML&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// Dati Base x la deserializzazione&lt;/span&gt;
        &lt;span class="rem"&gt;/// if set to true [pXML è un oggetto serializzato] se false è un path.&lt;/span&gt;
        &lt;span class="rem"&gt;/// Ritorna: Un oggetto di tipo MenuItem&lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="rem"&gt;/// &lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ConsoleItemColor ReadXml(&lt;span class="kwrd"&gt;string&lt;/span&gt; pXml, &lt;span class="kwrd"&gt;bool&lt;/span&gt; pIsXmlData)
        {
            ConsoleItemColor ret = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                ObjSerializer so = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObjSerializer();
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (!pIsXmlData)
                {
                    Stat.CheckEmptyPath(pXml);
                    Stat.CheckNoFile(pXml);
                    ret = (ConsoleItemColor)so.DeserializeFromFile(&lt;br /&gt;			&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ConsoleItemColor), pXml);
                } &lt;span class="rem"&gt;// if&lt;/span&gt;
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                {
                    ret = (ConsoleItemColor)so.DeserializeFromString(&lt;br /&gt;			&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ConsoleItemColor), pXml);
                }
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassNameS + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name + &lt;span class="str"&gt;" "&lt;/span&gt; + ex.Message, ex);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; INotifyPropertyChanged Implementazione &lt;span class="kwrd"&gt;event&lt;/span&gt; handler

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Evento che viene generato &lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Argomenti relativi all'evento&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPropertyChanged(PropertyChangedEventArgs e)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                PropertyChanged(&lt;span class="kwrd"&gt;this&lt;/span&gt;, e);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IComparable Members

        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// Compara 2 item color&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; CompareTo(&lt;span class="kwrd"&gt;object&lt;/span&gt; obj)
        {
            &lt;span class="kwrd"&gt;int&lt;/span&gt; ret = -1;
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (obj &lt;span class="kwrd"&gt;is&lt;/span&gt; ConsoleItemColor)
                {
                    ConsoleItemColor val = (ConsoleItemColor)obj;
                    &lt;span class="kwrd"&gt;int&lt;/span&gt; textCompare = &lt;span class="kwrd"&gt;this&lt;/span&gt;.TextColor.CompareTo(val.TextColor);
                    &lt;span class="kwrd"&gt;int&lt;/span&gt; screenCompare = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ScreenColor.CompareTo(val.ScreenColor);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (textCompare != 0)
                    {
                        ret = textCompare;
                    }
                    &lt;span class="kwrd"&gt;else&lt;/span&gt;
                    {
                        ret = screenCompare;
                    }
                }
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ApplicationException(&lt;span class="str"&gt;" "&lt;/span&gt; + mClassName + &lt;span class="str"&gt;"."&lt;/span&gt;
                    + System.Reflection.MethodBase.GetCurrentMethod().Name, ex);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; (ret);
        }
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;E qui abbiamo la nostra ultima fatica, ovvero l'implementazione di CompareTo, per comparare 2 oggetti e definirli uguali, siamo noi a decidere come procedere, in questo caso, due oggetti di tipo ConsoleItemColor sono uguali se hanno lo stesso colore per il testo e lo stesso colore per lo schermo. Inoltre abbiamo stabilito che un ConsoleItemColor è Maggiore di un'altro se ha il colore del Testo maggiore di quello dell'item con cui è comparato, quando i colori del testo fossero uguali, allora il colore dello schermo maggiore ci indica chi è il maggiore dei due. Come stabilire se un colore è maggiore o minore? I ConsoleColor sono una enumerazione intera che va da 0 a 15 pertanto stabiliamo la loro dimensione cercandone il valore numerico. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }
}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Conclusione: Questo è ovviamente solo un modo per implementare gli operatori di Uguaglianza e di Precedenza su un oggetto di tipo Entity, ciascuno può scegliere di implementarli come preferisce, è necessario però prestare attenzione a come si scrivono questi metodi affinché l'oggetto si comporti poi come vogliamo noi all'interno di un programma. &lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/gethashcode/default.aspx"&gt;GetHashCode&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/classi/default.aspx"&gt;Classi&lt;/a&gt; &lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/71.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2008/03/24/due-parole-su-gethashcode-e-sugli-operatori-di-uguaglianza-storico.aspx</guid>
            <pubDate>Mon, 24 Mar 2008 20:43:22 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/71.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2008/03/24/due-parole-su-gethashcode-e-sugli-operatori-di-uguaglianza-storico.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/71.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Come pubblicare assembly in GAC sfruttando i Post Build Events di Visual Studio(Storico)</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2008/03/24/come-pubblicare-assembly-in-gac-sfruttando-i-post-build-events.aspx</link>
            <description>&lt;p&gt;Nelle installazioni delle mie applicazioni sui computer dei miei clienti, non utilizzo mai la GAC per le mie librerie, questo perché non sono abbastanza brava da garantire la Compatibilità fra le DLL che compilo oggi e quelle che compilerò fra un mese, quindi, mettendo le librerie in GAC rischierei di mandare in crash una applicazione perché la nuova libreria installata con una seconda applicazione ha qualche metodo o qualche classe diversa da quella delle applicazioni precedentemente installate. &lt;/p&gt;
&lt;p&gt;Perciò, per chi come me pone tutte le classi base e gli helper comuni a tutti i programmi in una serie di DLL, consiglio l'uso della GAC nelle installazioni se e solo se siete così disciplinati da essere certi al cento per cento che una applicazione installata con la build 1.0 funzioni anche con la 2.0, oppure, siate così bravi da inserire il file di configurazione applicazione che indichi in modo specifico la versione della libreria da usare. &lt;/p&gt;
&lt;p&gt;A livello di sviluppo software invece, la GAC è molto utile ed io la uso sul mio PC per tutte le librerie comuni alle mie applicazioni in fase di sviluppo, infatti in questo modo è possibile trovare tutte le librerie automaticamente caricate nel tab .NET della form di inserimento dei riferimenti invece di doverle andare a cercare nei meandri delle cartelle ove abbiamo annidato i nostri progetti. Inoltre quando modifico una libreria di base, basta ricompilare tutte le applicazioni e sono aggiornate con la nuova versione, inoltre immediatamente mi danno errore se ho combinato qualche disastro eliminando/rinominando metodi e classi e sicuramente mi accorgo subito se le modifiche alla DLL vanno a fare esplodere i programmi che le usano, soprattutto se sono così brava da utilizzare gli Unit Test. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_addreference01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="192" alt="o_addreference01" width="244" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_addreference01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Questa è la lista di alcune delle mie librerie installate in GAC, però, per far comparire le librerie in questa lista, non basta semplicemente registrarle in GAC, perché Visual Studio è un po' cattivello e per comporre questa lista, ha bisogno di una chiave sul registry che gli indica quali sono le cartelle su cui andare a leggere le librerie della GAC. &lt;/p&gt;
&lt;p&gt;La chiave del registry in questione si trova sotto &lt;/p&gt;
&lt;pre class="MshFormat"&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_registry01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="244" alt="o_registry01" width="227" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_registry01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Come potete vedere è necessario creare una chiave su questa cartella, il cui valore contiene il percorso su cui si trovano le nostre DLL registrate in GAC. Lo script per creare questa chiave sul registry è il seguente:&lt;/p&gt;
&lt;pre class="MshFormat"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\NomeAzienda.Nomechiave]
@=&lt;span class="str"&gt;"C:\\CartellaDelleDllInGAC"&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;Se osservate l'immagine, per la chiave relativa alle mie librerie, ho imitato Infragistics (impariamo da chi c'è da più tempo di noi) chiamando la chiave con il Nik della mia azienda, il tipo di dll (Win/Web) e la versione delle stesse. Il nome della cartella ovviamente è il path completo della cartella dove si trovano le DLL. &lt;/p&gt;
&lt;p&gt;Visto che andare a modificare chiavi sul registry è qualcosa da fare con un po' di attenzione, per non dover registrare una per una tutte le cartelle dei miei progetti DLL, ho creato un unica cartella dove pubblico le DLL che registro in cache. &lt;br /&gt;
A questo punto, l'obiezione è "Ma che noia, copiare la libreria a manina sulla cartella e poi registrarla in GAC". &lt;br /&gt;
Per evitare le cose noiose i programmatori sono bravissimi e quelli di Microsoft hanno predisposto sui progetti di Visual Studio il necessario per darci una mano. &lt;/p&gt;
&lt;p&gt;Ciò che possiamo usare per automatizzare queste operazioni sono i &lt;strong&gt;&lt;em&gt;Post Build Events&lt;/em&gt;&lt;/strong&gt; di &lt;strong&gt;&lt;em&gt;Visual studio&lt;/em&gt;&lt;/strong&gt;, in VB non li avevano messi nella versione 2003 (lo so lo so vi maltrattano), ma nella versione 2005 si sono resi conto che in VB non si fanno solo programmini da dilettanti quindi sono stati aggiunti, un pochino nascosti ma li trovate qui. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_Buildeventsvb01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="185" alt="o_Buildeventsvb01" width="244" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_Buildeventsvb01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;La finestra si apre con il tastino che ho evidenziato e permette di gestire sia cose da fare prima di compilare che cose da fare dopo. Le cose da fare prima potrebbero ad esempio essere l'aggiornare dei files di contenuti (magari gli help e altro) che non sono di nostra competenza e devono essere aggiornati automaticamente. Nelle cose da fare dopo invece una delle più utili è l'automatizzazione della pubblicazione, che può anche essere un mezzo per inserire in un area comune a tutti gli sviluppatori delle DLL aggiornate di un team, in modo che ciascuno possa scaricarle in locale e usarle. &lt;/p&gt;
&lt;p&gt;Prima di vedere come fare a realizzare il tutto, vediamo anche la versione &lt;strong&gt;C#&lt;/strong&gt; (un po' meno nascosta) &lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_buildeventscs01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="167" alt="o_buildeventscs01" width="244" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_buildeventscs01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Per darci ancor più una mano, i programmatori di Microsoft ci permettono di inserire negli script che possiamo chiamare prima e dopo la compilazione, una serie di Macro per recuperare dati relativi all'ambiente e al progetto senza dover riscrivere tutto a manina. Basta fare click sul bottone Edit Post-Build e appare questa finestra: &lt;/p&gt;
&lt;p&gt;&lt;a href="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_buildeventsmacros01_2.jpg"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="244" alt="o_buildeventsmacros01" width="188" border="0" src="http://community.dotnetwork.it/images/community_dotnetwork_it/sabrina/WindowsLiveWriter/ComepubblicareassemblyinGACsfruttandoiPo_12B8A/o_buildeventsmacros01_thumb.jpg" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Vi invito a curiosare e provare le varie opzioni per vedere l'effetto che fanno... Vediamo che cosa ho scritto io sul mio mini script:&lt;/p&gt;
&lt;pre class="MshFormat"&gt;call ..\..\publish.bat $(ConfigurationName) $(TargetName)&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;call &lt;/strong&gt;è un comando batch della console, serve per chiamare un file batch da un altro file batch perché in realtà questi script non sono altro che dei Batch di comandi. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;..\..\publish.bat &lt;/strong&gt;è il nome del file batch in cui ho inserito i comandi per la pubblicazione, il motivo del ..\..\ è che quando viene eseguita la chiamata, il sistema ha come current directory la cartella bin\debug oppure bin\release, pertanto dobbiamo risalire 2 livelli per trovare il file batch (uno solo per tutti) con i comandi per la pubblicazione che io ho inserito nella cartella di progetto. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$(ConfigurationName) &lt;/strong&gt;vale &lt;em&gt;Debug&lt;/em&gt; o &lt;em&gt;Release&lt;/em&gt; in base alla configurazione da noi scelta per la compilazione e ci aiuterà a comporre il nome della cartella ove si trova la dll da pubblicare. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$(TargetName) &lt;/strong&gt;E il nome dell'assembly che ci servirà per costruire i dati per pubblicare e registrare in GAC la nostra libreria. &lt;/p&gt;
&lt;p&gt;Ed ora, l'ultimo oggetto da esplorare, il file Batch publish.bat. &lt;/p&gt;
&lt;pre class="MshFormat"&gt;cd ..\.. 
call %windir%\system32\xcopy.exe bin\%1\%2.dll &lt;span class="str"&gt;"C:\DllPublish\*.*"&lt;/span&gt; /s/e/v/y 
call %windir%\system32\xcopy.exe bin\%1\%2.xml &lt;span class="str"&gt;"C:\DllPublish\*.*"&lt;/span&gt; /s/e/v/y 
call &lt;span class="str"&gt;"%ProgramFiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe"&lt;/span&gt; /u %2 
call &lt;span class="str"&gt;"%ProgramFiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe"&lt;/span&gt; /i bin\%1\%2.Dll
&lt;/pre&gt;
&lt;p&gt;Questo batch è stato creato in modo da essere generico, funziona copiandolo e incollandolo su un qualsiasi progetto di tipo DLL, vediamo in dettaglio che cosa fa:&lt;/p&gt;
&lt;pre class="MshFormat"&gt;cd ..\.. &lt;br /&gt;Questo comando sposta la current directory allo stesso livello del file batch &lt;/pre&gt;
&lt;pre class="MshFormat"&gt;%windir%&lt;br /&gt;il comando &lt;em&gt;%nome%&lt;/em&gt; rileva una delle Environment Variables che sono visibili dalla console dei comandi digitando&lt;br /&gt;c:\&amp;gt; SET &lt;/pre&gt;
&lt;pre class="MshFormat"&gt;In questo caso leggiamo la cartella di installazione di Windows, per comporre il luogo ove si trova il comando xcopy.exe&lt;/pre&gt;
&lt;pre class="MshFormat"&gt;bin\%1\%2.dll &lt;/pre&gt;
&lt;p&gt;Il comando &lt;em&gt;%n&lt;/em&gt; viene sostituito dal parametro della linea di comando passato al Batch file quindi in questo caso componiamo il nome della cartella e il nome della dll (ES. bin\Release\Mylibrary.dll)&lt;/p&gt;
&lt;pre class="MshFormat"&gt;%ProgramFiles%&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Questo comando, legge dove si trova la cartella Programmi del sistema per comporre il nome della cartella ove si trova l'utility di registrazione in GAC delle DLL&lt;/p&gt;
&lt;p&gt;Dopo aver spiegato le cose strane, vediamo come il nostro batch: &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;sposta la cartella corrente sulla cartella di progetto, &lt;/li&gt;
    &lt;li&gt;copia la DLL e il suo file di documentazione XML (che servirà per avere l'intellisense quando faremo ad essa riferimento nei nostri progetti) nella cartella di pubblicazione da noi scelta. &lt;/li&gt;
    &lt;li&gt;rimuove dalla GAC la DLL &lt;/li&gt;
    &lt;li&gt;registra in GAC la DLL &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Con questa serie di "Barbatrucchi", otteniamo di risparmiarci delle noiose operazioni nello sviluppo di progetti complessi, provo ad elencarne alcuni: &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Trasformiamo le nostre librerie di base  in una suite di oggetti a nostra disposizione per tutti i progetti. (se volete un esempio di cosa mettervi dentro leggete &lt;a href="http://www.visual-basic.it/articoli/scdcSenzaMani01.htm"&gt;Guarda, Senza Mani!&lt;/a&gt; ove abbiamo creato una struttura di librerie riusabili). &lt;/li&gt;
    &lt;li&gt;Abbiamo le librerie sempre a disposizione nel tab .NET per farvi riferimento. &lt;/li&gt;
    &lt;li&gt;Le nostre librerie in GAC sono tenute sempre aggiornate all'ultima versione. &lt;/li&gt;
    &lt;li&gt;Aggiungere una nuova libreria al gruppo delle librerie pubblicate è questione di qualche click, dobbiamo copiare e incollare il file batch &lt;strong&gt;publish.bat&lt;/strong&gt; sulla cartella di progetto e aggiungere la riga di comando al &lt;strong&gt;Post Build Event&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;&lt;strong&gt;&lt;font color="#ff0000" size="4"&gt;IMPORTANTE!&lt;/font&gt;&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Perche una libreria possa essere registrata in GAC deve essere dotata di uno Strong Name, ovvero deve essere firmata con una Chiave Binaria, per farlo, andate a guardare il tab Signing delle proprietà di progetto (usualmente l'ultimo nello stesso luogo ove abbiamo trovato i post build events).&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;Prometto che farò un post in merito in seguito. &lt;/p&gt;
&lt;p&gt;Spero di esservi stata utile, per qualsiasi errore o domanda, approfondimento, delucidazione, il modulo di feedback è in fondo al post.&lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/GAC/default.aspx"&gt;GAC&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/StrongName/default.aspx"&gt;Strongname&lt;/a&gt; &lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/70.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2008/03/24/come-pubblicare-assembly-in-gac-sfruttando-i-post-build-events.aspx</guid>
            <pubDate>Mon, 24 Mar 2008 20:18:19 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/70.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2008/03/24/come-pubblicare-assembly-in-gac-sfruttando-i-post-build-events.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/70.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Scrivere nel registry usando come scusa le sorgenti dati ODBC (Storico)</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2008/03/24/scrivere-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx</link>
            <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Ecco il secondo post dedicato al registry, nel primo che trovate &lt;a href="http://community.visual-basic.it/sabrina/archive/2007/04/03/18970.aspx"&gt;qui&lt;/a&gt; ho mostrato come leggere chiavi e valori dal registry, in questo post, genero una nuova origine dati ODBC generando una chiave e aggiungendo valori a 2 chiavi del Registry. &lt;/p&gt;
&lt;p&gt;Abbiamo visto come una origine dati ODBC, non sia altro che una serie di dati memorizzati nel registro di sistema, e abbiamo visto che .NET ci fornisce due oggetti per lavorare con il registry: &lt;/p&gt;
&lt;p&gt;La classe statica Registry che permette di accedere al registro di sistema e di leggere velocemente le sottochiavi principali, LocalMachine e CurrentUser, e la classe RegistryKey che ci permette di generare una chiave di registro, leggere una chiave esistente, aggiornare o generare valori per una chiave di registro. &lt;/p&gt;
&lt;p&gt;Per vedere come si genera una origine dati ODBC, alla form del progetto di test aggiungiamo 2 bottoni che chiameremo: btnGenOdbcNwSys e btnGenOdbcNwUser. Facciamo anche una modifica ai primi 2 bottoni che abbiamo generato e trasformiamo il contenuto di ciascuno in un metodo, trasformando in questo modo il codice: &lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnLeggiODBC_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            LeggiOdbcSys();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LeggiOdbcSys()
        {
            RegistryKey regKeySys = Registry.LocalMachine.CreateSubKey(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI"&lt;/span&gt;);
            &lt;span class="rem"&gt;//RegistryKey[] subKeys = regKey.GetSubKeyNames();&lt;/span&gt;

            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] keys = regKeySys.GetSubKeyNames();
            StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
            sb.AppendLine(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(&lt;span class="str"&gt;'-'&lt;/span&gt;, 30));
            sb.AppendLine(&lt;span class="str"&gt;"Lista ODBC di sistema trovati:"&lt;/span&gt;);
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; keys.Length; i++)
            {
                sb.AppendLine(keys[i]);
                RegistryKey odbcKey = regKeySys.OpenSubKey(keys[i]);
                &lt;span class="kwrd"&gt;string&lt;/span&gt;[] valueNames = odbcKey.GetValueNames();
                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = 0; j &amp;lt; valueNames.Length; j++)
                {
                    sb.AppendFormat(&lt;span class="str"&gt;"* \t {0}={1}"&lt;/span&gt;, valueNames[j], odbcKey.GetValue(valueNames[j]).ToString());
                    sb.AppendLine();
                }
            }
            sb.AppendLine(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(&lt;span class="str"&gt;'-'&lt;/span&gt;, 30));
            sb.AppendLine();
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.txtResult.Text = sb.ToString() + &lt;span class="kwrd"&gt;this&lt;/span&gt;.txtResult.Text;
        }&lt;/pre&gt;
&lt;p&gt;Facciamo lo stesso con il bottone che visualizza gli ODBC Utente, non ricopio il codice perché è ripetitivo, ma lo trovate sul progetto allegato. &lt;/p&gt;
&lt;p&gt;Veniamo ora alla funzione che ci interessa veramente, Questa funzione, genererà una origine dati ODBC fra le origini dati di sistema che si connette al database Northwind su un Server SQL 2005.&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnGenOdbcNwSys_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="str"&gt;"TestNorthwindSys"&lt;/span&gt;;
            RegistryKey regKeySysOdbcDrv = Registry.LocalMachine.CreateSubKey(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI\\{0}"&lt;/span&gt;, name));
            RegistryKey regKeySysOdbcList = Registry.LocalMachine.CreateSubKey(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI\\ODBC Data Sources"&lt;/span&gt;);

            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Database"&lt;/span&gt;, &lt;span class="str"&gt;"Northwind"&lt;/span&gt; );
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Description"&lt;/span&gt;, &lt;span class="str"&gt;"Test Odbc Northwind Sys"&lt;/span&gt; );
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Language"&lt;/span&gt;, &lt;span class="str"&gt;"Italiano"&lt;/span&gt; );
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Server"&lt;/span&gt;, &lt;span class="str"&gt;"myComputer"&lt;/span&gt; );
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Trusted_connection"&lt;/span&gt;, &lt;span class="str"&gt;"Yes"&lt;/span&gt; );
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Driver"&lt;/span&gt;, &lt;span class="str"&gt;"sqlncli.dll"&lt;/span&gt; );

            regKeySysOdbcList.SetValue( name, &lt;span class="str"&gt;"Sql Native Client"&lt;/span&gt; );

            LeggiOdbcSys();
        }&lt;/pre&gt;
&lt;p&gt;Questo codice, genera una nuova chiave che si chiama TestNorthwindSys come figlia della chiave contenente gli ODBC di sistema, genera una serie di valori che la definiscono sempre agganciati alla chiave TestNorthwindSys, e infine aggiunge la nuova origine dati ed il nome del suo Driver alla lista degli ODBC di sistema usando la chiave ODBC Data Sources posta sotto la chiave principale degli ODBC. &lt;/p&gt;
&lt;p&gt;Aggiungiamo lo stesso tipo di funzionalità però sulle origini dati Utente:&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnGenOdbcNwUser_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="str"&gt;"TestNorthwindUsr"&lt;/span&gt;;
            RegistryKey regKeySysOdbcDrv = Registry.CurrentUser.CreateSubKey(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI\\{0}"&lt;/span&gt;, name));
            RegistryKey regKeySysOdbcList = Registry.CurrentUser.CreateSubKey(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI\\ODBC Data Sources"&lt;/span&gt;);

            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Database"&lt;/span&gt;, &lt;span class="str"&gt;"Northwind"&lt;/span&gt;);
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Description"&lt;/span&gt;, &lt;span class="str"&gt;"Test Odbc Northwind Sys"&lt;/span&gt;);
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Language"&lt;/span&gt;, &lt;span class="str"&gt;"Italiano"&lt;/span&gt;);
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Server"&lt;/span&gt;, &lt;span class="str"&gt;"myComputer"&lt;/span&gt;);
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Trusted_connection"&lt;/span&gt;, &lt;span class="str"&gt;"Yes"&lt;/span&gt;);
            regKeySysOdbcDrv.SetValue(&lt;span class="str"&gt;"Driver"&lt;/span&gt;, &lt;span class="str"&gt;"sqlncli.dll"&lt;/span&gt;);

            regKeySysOdbcList.SetValue(name, &lt;span class="str"&gt;"Sql Native Client"&lt;/span&gt;);

            LeggiOdbcUser();

        }&lt;/pre&gt;
&lt;p&gt;Abbiamo cambiato il nome dell'ODBC e abbiamo cambiato la Root Key da Local Machine a CurrentUser, ma il codice è sempre lo stesso. &lt;/p&gt;
&lt;p&gt;Se provate a premere i bottoni sulla form e poi aprite la Gestione Origini Dati ODBC sul pannello di controllo, troverete le due nuove connessioni che possono essere testate e risultano funzionanti. &lt;/p&gt;
&lt;p&gt;N.B. E' indispensabile cambiare il parametro &lt;strong&gt;Server&lt;/strong&gt; con il nome del vostro PC o comunque il nome dell'istanza di SQL Server a cui vi collegate. &lt;/p&gt;
&lt;p&gt;Questo esempio utilizza una chiave del registry ben precisa, però con lo stesso metodo è possibile generare ed aggiornare chiavi del registry a qualunque liverllo, ovviamente se e solo se, l'utente che esegue il programma ha i necessari diritti per poterlo fare. &lt;/p&gt;
&lt;p&gt;Sono certa che far girare questa applicazione con un utente non amministratore della macchina provocherà una serie di eccezioni. &lt;/p&gt;
&lt;p&gt;il link al progetto di test lo trovate &lt;a href="http://www.visual-basic.it/scarica.asp?ID=899"&gt;qui&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Qualunque domanda, osservazione, correzione, anatema, sarà bene accetto.&lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/registry/default.aspx"&gt;registry&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/classi/default.aspx"&gt;classi&lt;/a&gt; &lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/59.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2008/03/24/scrivere-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx</guid>
            <pubDate>Mon, 24 Mar 2008 17:59:55 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/59.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2008/03/24/scrivere-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/59.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Curiosare nel registry usando come scusa le sorgenti dati ODBC (Storico)</title>
            <link>http://community.dotnetwork.it/sabrina/archive/2008/03/24/curiosare-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx</link>
            <description>&lt;p&gt;Un paio di giorni fa, qualcuno ha chiesto sul forum come si genera da programma una origine dati ODBC, sapendo che il mio collega il Sistemaio usualmente inserisce nei login script la generazione delle origini dati ODBC necessarie al lavoro quotidiano degli utenti, gli ho chiesto se poteva darmi gli script, ovviamente, i suoi script sono in VBA visto che vengono eseguiti dal sistema al login, pertanto li ho presi come spunto per questo post, in cui vedremo come esaminare le origini dati ODBC che esistono su una macchina siano esse ODBC di sistema oppure ODBC Utente, usando .NET al posto di VBA. Ne seguirà un'altro, forse due, che mostreranno come generare l'origine dati ODBC da .NET &lt;/p&gt;
&lt;p&gt;Nello script del Sistemaio, nella sezione che genera gli ODBC di sistema c'era il seguente codice: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;cRegKey1 = "HKLM\Software\ODBC\ODBC.INI\" &amp;amp; trim(ssNome) &amp;amp; "\"&lt;br /&gt;
cRegKey2 = "HKLM\Software\ODBC\ODBC.INI\ODBC Data Sources\"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Assomigliano molto a due chiavi del registry, e il prefisso HKLM sembra indicare  HKey Local Machine, quindi, ne deduciamo che per vedere quali ODBC sono definiti su di un PC abbiamo bisogno di una chiave del registry. Visto che entrambe le chiavi qui sopra si trovano sotto ODBC\ODBC.INI, questa chiave sarà l'oggetto della mia curiosità: &lt;/p&gt;
&lt;p&gt;Il progetto di test, solo in C#, lo trovate in &lt;a href="http://www.visual-basic.it/scarica.asp?ID=899"&gt;Area Download&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;La soluzione OriginiDatiODBC contiene un solo progetto WindowsForms con lo stesso nome, in cui è una sola form &lt;strong&gt;FrmMain&lt;/strong&gt;. Nella form ho inserito i seguenti controlli: &lt;/p&gt;
&lt;p&gt;uno split container, due bottoni nel pannello 1, una textbox multilinea nel pannello 2 che riempie tutto il pannello. &lt;/p&gt;
&lt;p&gt;Il primo bottone, &lt;strong&gt;btnLeggiODBC&lt;/strong&gt;, ha il seguente codice sull'evento click:&lt;/p&gt;
&lt;pre&gt;        private void btnLeggiODBC_Click(object sender, EventArgs e)
        {
            RegistryKey  regKeySys = Registry.LocalMachine.CreateSubKey( "Software\\ODBC\\ODBC.INI" );
            string[] keys = regKeySys.GetSubKeyNames();
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(new string('-', 30)); 
            sb.AppendLine("Lista ODBC di sistema trovati:");
            for( int i=0; i&amp;lt; keys.Length; i++ )
            {
                sb.AppendLine(keys[i]);
                RegistryKey odbcKey = regKeySys.OpenSubKey(keys[i]);
                string[] valueNames = odbcKey.GetValueNames();
                for (int j = 0; j &amp;lt; valueNames.Length; j++)
                {
                    sb.AppendFormat("* \t {0}={1}", valueNames[j], odbcKey.GetValue(valueNames[j]).ToString());
                    sb.AppendLine();
                }
            }
            sb.AppendLine(new string('-', 30));
            sb.AppendLine();
            this.txtResult.Text = sb.ToString() + this.txtResult.Text;
        }&lt;/pre&gt;
&lt;p&gt;Cosa abbiamo fatto? Un metodo che lista tutte le chiavi del registry che si trovano su &lt;em&gt;LocalMachine\Software\ODBC\ODBC.INI&lt;/em&gt;, per farlo utilizziamo le classi RegistryKey e Registry che si trovano in Microsoft.Win32, Apriamo la chiave contenente i dati dell'ODBC, usando il metodo CreateSubKey della proprietà LocalMachine dell'oggetto Registry. &lt;/p&gt;
&lt;p&gt;Fatto questo, per listare che cosa c'è dentro alla chiave relativa agli ODBC, usiamo il metodo GetSubKeyNames per ottenere i nomi di tutte le chiavi che si trovano sotto alla chiave principale. Proseguiamo poi preparando uno stringbuilder che ci permetterà di visualizzare il contenuto del registry, ed infine facciamo un ciclo sulla lista delle chiavi che abbiamo recuperato e per ognuna di esse, usiamo il metodo OpenSubKey per ottenere l'oggetto RegistryKey, e la funzione GetValueNames per ottenere tutti i nomi dei valori presenti in ciascuna delle chiavi, con un ciclo annidato aggiungiamo allo StringBuilder  i nomi dei valori ed il loro valore (non è un gioco di parole). &lt;/p&gt;
&lt;p&gt;Cosa otteniamo facendo click sul nostro bottone? Una lista di questo tipo: &lt;/p&gt;
&lt;p&gt;------------------------------&lt;br /&gt;
Lista ODBC di sistema trovati:&lt;br /&gt;
4UAHR&lt;br /&gt;
* Database=4UAHR&lt;br /&gt;
* Description=AHR - For You I.T.&lt;br /&gt;
* Driver=\sqlncli.dll&lt;br /&gt;
* Language=Italiano&lt;br /&gt;
* Server=4unb10&lt;br /&gt;
* Trusted_Connection=Yes&lt;br /&gt;
DBMIRROR&lt;br /&gt;
* Driver=C:\WINDOWS\system32\sqlncli.dll&lt;br /&gt;
* Description=Connessione al DBMIRROR MEXAL&lt;br /&gt;
* Server=rddev&lt;br /&gt;
* Database=DBMIRROR&lt;br /&gt;
* LastUser=scosolo&lt;br /&gt;
* Trusted_Connection=Yes&lt;br /&gt;
GlobalCar&lt;br /&gt;
* DBQ=C:\Programmi\Macromedia\Dreamweaver MX\Samples\Database\global.mdb&lt;br /&gt;
* Description=Data Source for the Compass Travel tutorial site.&lt;br /&gt;
* Driver=C:\WINDOWS\system32\odbcjt32.dll&lt;br /&gt;
* DriverId=25&lt;br /&gt;
* FIL=MS Access;&lt;br /&gt;
* SafeTransactions=0&lt;br /&gt;
* UID=&lt;br /&gt;
ODBC Data Sources&lt;br /&gt;
* DBMIRROR=SQL Native Client&lt;br /&gt;
* GlobalCar=Microsoft Access Driver (*.mdb)&lt;br /&gt;
* PUBS=SQL Native Client&lt;br /&gt;
* 4UAHR=SQL Native Client&lt;br /&gt;
ODBC File DSN&lt;br /&gt;
* DefaultDSNDir=C:\Programmi\File comuni\ODBC\Data Sources&lt;br /&gt;
PUBS&lt;br /&gt;
* Driver=C:\WINDOWS\system32\sqlncli.dll&lt;br /&gt;
* Description=Connect to Pubs Database&lt;br /&gt;
* Server=4unb10&lt;br /&gt;
* Database=pubs&lt;br /&gt;
* LastUser=scosolo&lt;br /&gt;
* Trusted_Connection=Yes&lt;br /&gt;
------------------------------ &lt;/p&gt;
&lt;p&gt;Quelle contrassegnate in Azzurro, sono le origini dati ODBC di sistema inserite sul mio PC, ciascuna contiene al suo interno come valori le seguenti informazioni: &lt;/p&gt;
&lt;p&gt;Il Driver, usualmente una DLL che si trova su WINDOWS\System32, poi dei parametri diversi a seconda del tipo di driver, in questo caso sono di 2 soli tipi, driver per SQL Server 2005 e il driver per il tutorial di DreamWeaver MX che invece è un file access. Ogni origine dati ha una Descrizione, ed alcuni parametri variabili che permettono al driver di comporre la stringa di connessione a quel tipo di sorgente dati. &lt;/p&gt;
&lt;p&gt;Le chiavi contrassegnate in Rosso, non sono origini dati, sono invece delle chiavi di configurazione per la gestione degli ODBC, infatti, ODBC Data Sources contiene la lista degli ODBC con il nome del driver ad essi associato, mentre  ODBC File DSN contiene la cartella che ospita i DSN salvati su file. &lt;/p&gt;
&lt;p&gt;Il secondo bottone btn_LeggiODBCUsr, fa qualcosa di simile a quel che fa il primo bottone, però, invece di partire da LocalMachine, parte da CurrentUser, l'oggetto che rappresenta i dati di configurazione del registro per l'utente correntemente loggato. Questo, ci permette di ottenere ed osservare, i dati di configurazione ODBC utente.&lt;/p&gt;
&lt;pre class="CSharpFormat"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; btnLeggiODBCUsr_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            RegistryKey regKeyUsr = Registry.CurrentUser.CreateSubKey(&lt;span class="str"&gt;"Software\\ODBC\\ODBC.INI"&lt;/span&gt;);
            StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
            sb.AppendLine(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(&lt;span class="str"&gt;'-'&lt;/span&gt;, 30));
            sb.AppendLine(&lt;span class="str"&gt;"Lista ODBC utente trovati:"&lt;/span&gt;);
            &lt;span class="kwrd"&gt;string&lt;/span&gt;[]  keys = regKeyUsr.GetSubKeyNames();
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; keys.Length; i++)
            {
                sb.AppendLine(keys[i]);
                RegistryKey odbcKey = regKeyUsr.OpenSubKey(keys[i]);
                &lt;span class="kwrd"&gt;string&lt;/span&gt;[] valueNames = odbcKey.GetValueNames();
                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j = 0; j &amp;lt; valueNames.Length; j++)
                {
                    sb.AppendFormat(&lt;span class="str"&gt;"* \t {0}={1}"&lt;/span&gt;, valueNames[j], odbcKey.GetValue(valueNames[j]).ToString());
                    sb.AppendLine();
                }
            }
            sb.AppendLine(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(&lt;span class="str"&gt;'-'&lt;/span&gt;, 30));
            sb.AppendLine();

            &lt;span class="kwrd"&gt;this&lt;/span&gt;.txtResult.Text = sb.ToString() + &lt;span class="kwrd"&gt;this&lt;/span&gt;.txtResult.Text;

        }&lt;/pre&gt;
&lt;p&gt;Anche questo metodo, come il precedente utilizza le classi Registry, RegistryKey, ed i metodi CreateSubKey, GetSubKeyNames, OpenSubKey, GetValueNames, GetValue per ottenere le informazioni sul contenuto della chiave del Registry e dei suoi sottolivelli che a noi interessano. &lt;/p&gt;
&lt;p&gt;Cosa otteniamo premendo il tasto sulla form? &lt;/p&gt;
&lt;p&gt;------------------------------&lt;br /&gt;
Lista ODBC utente trovati:&lt;br /&gt;
ahrdemo&lt;br /&gt;
* Driver=C:\WINDOWS\system32\SQLSRV32.dll&lt;br /&gt;
* Description=ADHOC REVOLUTION&lt;br /&gt;
* Server=(local)&lt;br /&gt;
* Database=ahrdemo&lt;br /&gt;
* LastUser=sa&lt;br /&gt;
* Trusted_Connection=Yes&lt;br /&gt;
dBASE Files&lt;br /&gt;
* UID=&lt;br /&gt;
* SafeTransactions=0&lt;br /&gt;
* DriverId=533&lt;br /&gt;
* Driver=C:\PROGRA~1\FILECO~1\MICROS~1\OFFICE12\ACEODBC.DLL&lt;br /&gt;
Excel Files&lt;br /&gt;
* UID=&lt;br /&gt;
* SafeTransactions=0&lt;br /&gt;
* DriverId=1046&lt;br /&gt;
* Driver=C:\PROGRA~1\FILECO~1\MICROS~1\OFFICE12\ACEODBC.DLL&lt;br /&gt;
MS Access Database&lt;br /&gt;
* UID=&lt;br /&gt;
* SafeTransactions=0&lt;br /&gt;
* DriverId=25&lt;br /&gt;
* Driver=C:\PROGRA~1\FILECO~1\MICROS~1\OFFICE12\ACEODBC.DLL&lt;br /&gt;
ODBC Data Sources&lt;br /&gt;
* Visio Database Samples=Microsoft Access Driver (*.MDB)&lt;br /&gt;
* ahrdemo=SQL Server&lt;br /&gt;
* dBASE Files=Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx)&lt;br /&gt;
* Excel Files=Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)&lt;br /&gt;
* MS Access Database=Microsoft Access Driver (*.mdb, *.accdb)&lt;br /&gt;
Visio Database Samples&lt;br /&gt;
* SafeTransactions=0&lt;br /&gt;
* DefaultDir=""&lt;br /&gt;
* DBQ=C:\PROGRA~1\MICROS~2\Visio11\1040\DBSAMPLE.MDB&lt;br /&gt;
* DriverId=25&lt;br /&gt;
* Driver=C:\WINDOWS\system32\\odbcjt32.dll&lt;br /&gt;
* UID=&lt;br /&gt;
* ReadOnly=System.Byte[]&lt;br /&gt;
------------------------------ &lt;/p&gt;
&lt;p&gt;Anche in questo caso, in Blu abbiamo gli ODBC utente memorizzati sulla macchina e invece in rosso abbiamo la chiave ODBC Data Sources che contiene la lista degli ODBC ed il nome del driver ad essi associato. &lt;/p&gt;
&lt;p&gt;Facciamo il riassunto di quello che abbiamo scoperto con la scusa della gestione degli ODBC: &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Il namespace &lt;strong&gt;Microsoft.Win32&lt;/strong&gt; che contiene classi per la gestione del sistema &lt;/li&gt;
    &lt;li&gt;la classe statica &lt;strong&gt;Registry&lt;/strong&gt; che fornisce proprietà che danno accesso alle principali chiavi del registro di sistema
    &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;LocalMachine&lt;/strong&gt; Proprietà statica che fornisce l'accesso a &lt;em&gt;HKey Local Machine&lt;/em&gt; &lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;CurrentUser&lt;/strong&gt; Proprietà statica che fornisce l'accesso a &lt;em&gt;HKey Current User&lt;/em&gt; &lt;/li&gt;
    &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;la classe &lt;strong&gt;RegistryKey&lt;/strong&gt; che permette di aprire e leggere una chiave di registro e ottenere informazioni o fare modifiche sulla chiave letta. &lt;/li&gt;
    &lt;li&gt;il metodo &lt;strong&gt;CreateSubKey&lt;/strong&gt; che permette di aprire una chiave esistente sul registro oppure di generarne una nuova. &lt;/li&gt;
    &lt;li&gt;il metodo &lt;strong&gt;GetSubKeyNames&lt;/strong&gt; che permette di ottenere una lista delle sottochiavi di una chiave di registro (se ne è provvista) &lt;/li&gt;
    &lt;li&gt;il metodo &lt;strong&gt;GetValueNames&lt;/strong&gt; che permette di ottenere una lista dei nomi dei valori di una chiave di registro (se ne è provvista) &lt;/li&gt;
    &lt;li&gt;il metodo &lt;strong&gt;GetValue&lt;/strong&gt; che permette di ottenere il valore di un valore (uff!) di una chiave di registro. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nel prossimo post, proveremo a generare una origine dati ODBC nuova e vedere l'effetto che fa... &lt;/p&gt;
&lt;p&gt;Tags: &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/registry/default.aspx"&gt;registry&lt;/a&gt;, &lt;a rel="tag" href="http://community.dotnetwork.it/Sabrina/Tags/classi/default.aspx"&gt;classi&lt;/a&gt; &lt;/p&gt;&lt;img src="http://community.dotnetwork.it/sabrina/aggbug/58.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Sabrina C.</dc:creator>
            <guid>http://community.dotnetwork.it/sabrina/archive/2008/03/24/curiosare-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx</guid>
            <pubDate>Mon, 24 Mar 2008 17:58:03 GMT</pubDate>
            <wfw:comment>http://community.dotnetwork.it/sabrina/comments/58.aspx</wfw:comment>
            <comments>http://community.dotnetwork.it/sabrina/archive/2008/03/24/curiosare-nel-registry-usando-come-scusa-le-sorgenti-dati-odbc.aspx#feedback</comments>
            <wfw:commentRss>http://community.dotnetwork.it/sabrina/comments/commentRss/58.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>
