giovedì 18 dicembre 2008

Operatori Cast e OfType di LINQ: usare LINQ su colllezioni non generics

Linq è nato per essere usato su collezioni che implementano IEnumerable.
Ad esempio su List

IList<int> mialista = new List<int>();

IEnumerable<int> result = mialista.Where(miovalore => miovalore==44).Select(miovalore => miovalore);



Ma come si può usare LINQ su collection di vecchio tipo? Ad esempio su una normalissima ArrayList ?
Usando l'operaatore Cast, oppure l'operatore OfType in questo modo:
poniamo di avere una ArrayList in cui inseriamo un pò di interi, ma anche una stringa.

ArrayList mialista = new ArrayList();

mialista.Add(44);

mialista.Add(55);

mialista.Add("pippo");


Ora vogliamo recuperare l'oggetto, o gli oggetti, di valore 44.
Dato che noi cerchiamo un intero, dobbiamo modificare la ArrayList in modo che diventi una IEnumerable.

Questo si ottiene usando Cast():

IEnumerable<int> listaGenerics =mialista.Cast<int>();
IEnumerable<int> result = listaGenerics.Where(miovalore => miovalore==44).Select(miovalore => miovalore);

oppure usando OfType():

IEnumerable<int> listaGenerics =mialista.OfType<int>();
IEnumerable<int> result = listaGenerics.Where(miovalore => miovalore == 44).Select(miovalore => miovalore);


La differenza è che Cast prova a castare tutti gli oggetti nella lista. Se non riesce a castare anche un solo oggetto lancia eccezione. Nel nostro caso quindi avremo un'eccezione dato che non riuscirà a castare ad intero la stringa "pippo".

Invece OfType si accontenta di castare solo gli oggetti che può castare. Gli altri vengono tralasciati e non vengono inseriti nella collection IEnumerable. Nel nostro caso la collection listaGenerics  conterrà solo i valori 44 e 55.

Prerequisiti per usare Linq To Object in un progetto C#


Per utilizzare le librerie .NET di LINQ to Object è necessario:

  • che il progetto abbia come target framework ".NET framework 3.5" o successivi (modificabile dalla finestra delle proprietà del progetto)
  • che il progetto includa fra le references quella a System.Data.Linq
  • che la classe che necessita di usare funzioni di Linq includa, tramite uno "using", il namespace System.Linq
A questo punto sarà possibile usare, su tutti gli oggetti che estendono IEnumerable, i metodi che Linq mette a disposizione. Son facilmente identificabili perchè sono extension methods, e dunque l'intellisense li visualizza in modo particolare. Il solito cubetto che contraddistingue il metodo ha associato una freccia blu rivolta verso il basso. Vedi figura qui sotto...

Gli oggetti su cui Linq to Object è utilizzabile sono tutti gli array (come int[],  MyCustomObject[], ...) , tutte le collezioni di generics (List ,...) e, con un minimo adattamento, anche sulle collezioni non-generics, usando gli operatori Cast  e OfType.

martedì 16 dicembre 2008


Su questo sito


c'è una serie di test di programmazione passati i quali si diventa cintura nera di Java!!

Il bello è che i test sono creati dalla community in vero spirito 2.0.

Io per ora sono solo cintura gialla...


venerdì 12 dicembre 2008

Component Diagram UML: le interfacce

Trovo che il Component Diagram sia il più utile dei diagrammi UML, poichè è chiaro,  facile da capire e sopratutto utile, dato che descrive come le varie parti di un'applicazione (component) interagiscono.

Può essere usato per descrivere l'interazione fra vari component, oppure fra le parti interne di un singolo component.

Vediamo un esempio di questo secondo tipo di uso.

Poniamo di avere un component (se si vuole concretizzare, una dll) che serve per la modellizzazione di un negozio.

Riporto qui un esempio preso dal sito di Rational - IBM (articolo completo) .



La figura rappresenta il component diagram della struttura interna e delle interfaccie verso l'esterno del componente "Store".

Nella simbologia UML 2.0, un' interfaccia esposta si disegna con un "lollipop" (un  "lecca-lecca")  cioè una linea dritta con un pallino in cima.
Invece, un'interfaccia richiesta si simboleggia con un "socket" cioè una linea con un mezzio cerchio in cima. 
Ovviamente lollipop e socket sono fatti per "agganciarsi" uno nell'altro.



(qui sopra Notazione UML 2.0)
(qui sopra Notazione UML 1)

Se pensiamo alla classe "Customer", possiamo dire che sicuramente avrà un'interfaccia "Person" attraverso la quale può esporre le sue proprietà interne. Un'interfaccia di questo tipo conterrà metodi come getName() oppure getPersonData()...
Possiamo dire quindi che "Customer" espone un'interfaccia verso l'esterno. Dunque dal rettangolo della classe Customer esce un lollipop chiamato "Person".

Discorso parallelo per "Product" che espone un'interfaccia (un lollipop) chiamata"OrderableItem". Questa interfaccia avrà metodi come getPrice() o getItemDescription()...

Guardiamo ora la classe "Order". Un ordine, per essere definito, deve avere il riferimento del prodotto acquistato e del cliente acquirente. Dunque, nella classe "Order"esisteranno dei metodi che richiedono come parametri delle istanze di  "Person" e "OrderableItem". Da "Order" escono quindi due socket, a simboleggiare le due interfaccia richieste.

    interface Person { }

    interface OrderableItem { }

    class Order

    { // Order richiede (ad esempio attraverso il costruttore) l'uso di due istanze delle interfacce Person e OrderableItem

       public Order(Person p, OrderableItem o) {       

        }

    }

    class Customer : Person {    }

    class Product : OrderableItem {    }


Collegando i socket con i lollipop si ottiene il collegamento fra le tre classi che costituiscono il componente. 




Ma il componente può avere interfaccie verso l'esterno.

Ad esempio l'interfaccia Account serve per collegare il Customer con i dati del conto di pagamento, gestiti da un altro componente. L'interfaccia account avrà metodi come: getAccountData(), ...
Un customer deve conoscere questi dati, dunque ha un'interfaccia rischiesta (socket) verso l'esterno del componente.

Il componente può esser parte di più programmi (un programma web di invio ordini da un sito internet, un programma di contabilità, un programma di data-mining....). In ogni caso dovrà esporre verso l'esterno un'interfaccia che riassuma i dati dell'ordine, chiamata "OrderEntry". Essa avrà metodi come: getTotalPrice(), getDateOfOrder(), ...

Dunque la classe "Order" espone vesro l'esterno del componente un lollipop chiamato "OrderEntry".  

martedì 9 dicembre 2008

Aggiungere un TraceListener ad una classe da codice

Vogliamo aggiungere un listener del Trace di una applicazione. Sebbene questa operazione si possa eseguire direttamente dal file di configurazione dell'applicazione (App.config), preferisco gestirla da codice, in modo da avere un maggiore controllo ed una maggiore comprensione su quello che accade.

Il Trace è il modo migliore per gestire i log in .NET . Per info cercare informazioni su msdn alla voce TraceSource.

Nel file App.config (se non esiste, va creato nella directory base del progetto) bisogna definire un "source" avente come nome, il nome che daremo al nostro Trace. In questo caso "ApplicationTraceName".
Poi bisogna associare al source uno "switch", che serve ad indicare il livello minimo di ascolto rispetto a questa source. In questo caso "Verbose", cioè ascoltiamo tutto ciò che la source notifica.
E' ovviamente possibile gestire più di una source.

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

<configuration>

  <system.diagnostics>

    <sources>   

      <source name="ApplicationTraceName" switchName="VerboseSwitch">      

      source>     

    sources>

    <sharedListeners>     

    sharedListeners>

    <switches>

      <add name="VerboseSwitch" value="Verbose" />

    switches>

  system.diagnostics>

configuration>




Definiamo ora la sorgente del flusso di Trace. Deve essere una classe che fa da wrapper alla classe TraceSource. Deve avere un metodo per registrare un listener ed un metodo per lanciare un nuovo evento di Trace. Il nome affibiato al TraceSource deve essere quello dichiarato nell' App.config. 

        public static class ApplicationTrace

        {

            static private System.Diagnostics.TraceSource Source = new System.Diagnostics.TraceSource("ApplicationTraceName");

             ///

            ///     Writes a trace event message to the trace listeners in the

            ///     System.Diagnostics.TraceSource.Listeners

            ///     collection using the specified event type, event identifier, and message.

            ///

            ///

One of the System.Diagnostics.TraceEventType values

            ///  that specifies the event type of the trace data.

            ///

A numeric identifier for the event.

            ///

The trace message to write.

            [System.Diagnostics.Conditional("TRACE")]

            static public void TraceEvent(System.Diagnostics.TraceEventType eventType, int id, string message)

            {

                Source.TraceEvent(eventType, id, message); Source.Flush();

             }

            ///

            /// Add a listener to the trace

            ///

            ///

            static public void AddListener(System.Diagnostics.TraceListener listener)

            {

                Source.Listeners.Add(listener);

            }

      }


Definita la sorgente del flusso di Trace, da codice creiamo il listener che ascolta il flusso di dati e lo scrive da qualche parte. Per fare questo usiamo gli oggetti del namespace System.Diagnostic di .NET

System.Diagnostics.ConsoleTraceListener traceListener = new System.Diagnostics.ConsoleTraceListener();

//impostiamo il verbose level

traceListener.Filter = new System.Diagnostics.EventTypeFilter(System.Diagnostics.SourceLevels.Verbose);

Nota: qui avremmo potuto definire un filtro più restrittivo, ad esempio a livello Information. 


Infine, colleghiamo il listener creato alla sorgente di Trace usando il metodo della sorgente per l'aggiunta di listener:

ApplicationTrace.AddListener(traceListener);

Abbiamo terminato. Ora, ogni volta che verrà invocato il metodo TraceEvent, l'evento sarà tracciato a Console.

ApplicationTrace.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "my message");



Il codice completo è questo:

public class MyClass{

        public MyClass()

        {

            System.Diagnostics.ConsoleTraceListener traceListener = new System.Diagnostics.ConsoleTraceListener();

            //information  level

            traceListener.Filter = new System.Diagnostics.EventTypeFilter(System.Diagnostics.SourceLevels.Verbose);        

            ApplicationTrace.AddListener(traceListener);

        }

         public void myMethod() {

            ApplicationTrace.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "my message");

        }

    }

  static void Main(string[] args)

        {

            MyClass myClass = new MyClass();

            myClass.myMethod();

            Console.ReadLine();

}


Infine, si può pensare di voler redirigere il flusso del Trace verso un altro output che non sia la console, ad esempio scrivendo su un file di log. Per fare questo basta ridefinire in questo modo il listener:

          System.Diagnostics.TextWriterTraceListener traceListener = new System.Diagnostics.TextWriterTraceListener("myfilename.txt");


Ovviamente si può creare un insieme di listener a piacere, in modo da scrivere il log su più destinazioni diverse (files, console, maschere a video, pagine web...) anche a livelli di log differenti.

mercoledì 3 dicembre 2008

Nested class/ Inner class differenza fra C# e Java

Nested o Inner class sono classi definite all'interno del corpo di un'altra classe (Outer class).

Per una introduzione sulle Nested class in C# vedere il post precedente.

Diciamo subito una cosa:
In C# esiste solo il concetto di Nested class, mentre in Java esistono sia le Nested class sia le Inner class.

In Java:
Vediamo che differenza c'è fra Inner class e Nested class in Java: le Nested class sono delle Inner class statiche.

Inner class:

public class OuterClass{

public class InnerClass{

}

}



Nested class:


public class OuterClass{

public static class NestedClass{

}

}



La differenza è la stessa che c'è fra un metodo statico o non statico...
L'istanza di una inner class appartiene ad un'istanza della outer class, mentre l'istanza di una nested class non ha un'istanza associata.

L'inner class si invoca così:

OuterClass outer = new OuterClass();     OuterClass.InnerClass inner = outer.new OuterClass.InnerClass();

La nested class si invoca così:

    OuterClass.NestedClass nested = new OuterClass.NestedClass();

Si noti che la Inner class ha accesso a tutti i metodi/variabili della Outer class, anche se definiti privati. Questo perchè p intimamente legata all'instanza della Outer class da cui è stata creata.
La Nested class invece, può accedere solo ai metodi/variabili static della Outer class.



In C#

La Nested class di C# ha lo stesso significato semantico della Nested class di java: è una classe statica definita dentro un'altra classe. La differenza è, se vogliamo, solo sintattica: infatti in C# viene omesso il modificatore "static" ed una Nested class si definisce così:

public class OuterClass
    {
        public class NestedClass {

        }
    }

Anche in questo caso la Nested class può accedere solo ai metodi static della Outer class.

Ricordo ancora che il concetto di Inner class in C# non è previsto.

Nested class in C#

Una Nested class è una classe definita all'interno del codice di un'altra classe (Outer class).


Ad esempio:

  class OuterClass
    {
  
        class NestedClass {

         
        }
    }

Come usare la Nested class dall'esterno

La classe interna può essere referenziata dall'esterno in questo modo:

OuterClass. NestedClass  myObj = new OuterClass. NestedClass();//non compila perchè NestedClass è private

ma solo se è definita public!! ( Il valore di default dell'access modifier di una nested class è private). Dunque la precedente riga di codice non compila a meno di definire così la nested class:


  class OuterClass
    {
  
        public class NestedClass {
         
        }
    }


Ora si può usare con successo:
OuterClass. NestedClass  myObj = new OuterClass. NestedClass();//ok!!


Nota, si potrebbe essere tentati di usare un'istanza della outer class per definire la nested class, come in questa chiamata, ma non è corretto dato che  è come se la nested class fosse un membro statico della outer:
OuterClass. NestedClass  myObj =(new OuterClass()).NestedClass(); //non compila, non si può chiamare in questo modo.


Come usare usare la Outer class dall'interno della Nested class

Il principale motivo per cui si inserisce una classe dentro un'altra è quello di utilizzare membri e variabili della Outer class dall'interno della Nested class.
Attenzione:  dalla Nested class si possono utilizzare solo i membri static della Outer class!!! 

La sintassi è questa: OuterClass.membro 

    class OuterClass
    {
        private string myOuterString;

        private static string myOuterStaticString;


        public class NestedClass {

            public void Method() {

                OuterClass.myOuterStaticString="ciao";//ok!

                OuterClass.myOuterString = "ciao";//No, questa riga non compila, dato che myOuterString  non è static
            }
        }
    }

Nota che la Nested class accede ai membri della Outer class anche se questi sono privati!!! Questa è la grande potenza delle nested class e l'unico motivo per cui andrebbero usate.

lunedì 1 dicembre 2008

Anni bisestili in C#

 Capire se un anno è bisestile (leap year) o no in C# è banale grazie al metodo isLeapYear della classe DateTime


public static bool IsLeapYear(int year);


Ad esempio 

DateTime.IsLeapYear(1993);

torna, ovviamente, false.

Lettori fissi