venerdì 26 novembre 2010

From string to stream...

Alcune situazioni sembrano davvero fatte per rendere le cose complesse..

Vi porto quest'esmpio atto ad un processo di validazione di un testo XML.
Questo è contenuto in una string che è passata a questo metodo come
parametro.

In un primo momento mi è sembrato corretto affrontare la soluzione così.

XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.Schemas.Add("http://cSharp.org", Path.Combine(_xmlRequestPath, ValidatorFileName));
xmlSettings.ValidationType = ValidationType.Schema;

XmlReader xR = XmlReader.Create(dataDocument, xmlSettings);

Tuttavia questa soluzione propone un errore che sembra davvero incomprensibile ..
"CARATTERI NON VALIDI NEL PERCORSO"...
Già perchè utilizzando il metodo XmlReader.Create(string,XmlSettings) ci si che per il
primo parametro non ci sia il nudo e crudo XML .. ma il percorso

Acc.. ma io non ho il percorso ho una stringa...

A questo punto dopo aver letto le varie firme di XmlReader.Create scopro che si può
utilizzare uno stream ... e quindi non rimane altro che convertire una
stringa in Stream.

Efficace e di concetto c'e' il memory stream certo magari occupa un po di ram,
ma è sempre meglio che ipotizzare di salvarsi il file in una cartella temporanea,
accedervi e cancellarlo...

XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.Schemas.Add("http://cSharp.org", Path.Combine(_xmlRequestPath, ValidatorFileName));
xmlSettings.ValidationType = ValidationType.Schema;

MemoryStream msx = new MemoryStream(Encoding.UTF8.GetBytes(dataDocument));

XmlReader xR = XmlReader.Create(msx, xmlSettings);

E' chiaro che msx dovrà essere messo a null non appena non servirà più ...

mercoledì 24 novembre 2010

XmlSerializer ,list ,CollectionBase, Array

Meno male che ho 5 min per postare quest'esempio.. il cui prò ha poco senso, ma potrebbe chiarire qualche cosa su come si comporta la serializzazione in xml...

Come sempre il post sarà lunghetto, armatevi di pazienza e buona lettura.

partiamo da una cosa semplice un Entity più o meno banale.

public class Entity
{
#region Private
private int _UserID;
private string _UserName;
private string _UserSurname;
private DateTime _UserBirth;
private string _UserAddress;
#endregion


#region Public
public int UserID
{
get { return _UserID; }
set { _UserID = value; }
}

public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}

public string UserSurname
{
get { return _UserSurname; }
set { _UserSurname = value; }
}

public DateTime UserBirth
{
get { return _UserBirth; }
set { _UserBirth = value; }
}

public string UserAddress
{
get { return _UserAddress; }
set { _UserAddress = value; }
}
#endregion
}

Nulla di davvero eccezionale...

Quindi passiamo alle possibili collezioni ...

public class Entities:List
{
}

public class collectionEntities : System.Collections.CollectionBase
{
public void Add(Entity et)
{
this.List.Add(et);
}
}


public class GenericEntities
{

public class Item
{
private Item next;

private T data;


public Item Next
{
get { return next; }
set { next = value; }
}


public T Data
{
get { return data; }
set { data = value; }
}


public Item(T t)
{
next = null;
Data = t;
}
}

private Item Element;

public GenericEntities()
{
Element = null;
}

public void Add(T t)
{
Item i = new Item(t);
i.Next = Element;
Element = i;
}

public IEnumerator GetEnumerator()
{
Item current = Element;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}

e quindi i serializer ...

public static class SerializerTool
{
public static string Serialize(Entities eList)
{
XmlSerializer xmls = new XmlSerializer(typeof(Entities));


StringWriter sw = new StringWriter();

xmls.Serialize(sw, eList);


return sw.ToString();
}

public static string Serialize(Entity[] eList)
{
XmlSerializer xmls = new XmlSerializer(typeof(Entity[]));


StringWriter sw = new StringWriter();

xmls.Serialize(sw, eList);


return sw.ToString();
}

public static string Serialize(collectionEntities eList)
{
XmlSerializer xmls = new XmlSerializer(typeof(collectionEntities));


StringWriter sw = new StringWriter();

xmls.Serialize(sw, eList);


return sw.ToString();
}

public static string Serialize(GenericEntities eList)
{
XmlSerializer xmls = new XmlSerializer(typeof(GenericEntities));


StringWriter sw = new StringWriter();

xmls.Serialize(sw, eList);


return sw.ToString();
}
}

bene questo è tutto quello che ci serve o quasi per il nostro esempio..

manca solo il main

class Program
{
static void Main(string[] args)
{

#region Entity Creation
Entity e1 = new Entity();

e1.UserName = "Mario";
e1.UserSurname = "Rossi";
e1.UserBirth = DateTime.Parse("01/01/1994");
e1.UserAddress = "via roma n1 ";


Entity e2 = new Entity();

e2.UserName = "Davide";
e2.UserSurname = "Bianchi";
e2.UserBirth = DateTime.Parse("05/05/1996");
e2.UserAddress = "via milano n2 ";

Entity e3 = new Entity();

e3.UserName = "Giorgio";
e3.UserSurname = "Verdi";
e3.UserBirth = DateTime.Parse("05/05/1996");
e3.UserAddress = "via torino n3";
#endregion


// LIST T
Entities el = new Entities();

el.Add(e1);
el.Add(e2);
el.Add(e3);

Console.WriteLine("List T");
Console.WriteLine(SerializerTool.Serialize(el));

Console.ReadLine();

// Array
Entity[] eA = new Entity[3];

eA[0] = e1;
eA[1] = e2;
eA[2] = e3;

Console.WriteLine("ARRAY");
Console.WriteLine(SerializerTool.Serialize(eA));

Console.ReadLine();

// collectionBase
collectionEntities eC = new collectionEntities();

eC.Add(e1);
eC.Add(e2);
eC.Add(e3);

Console.WriteLine("Collection");
Console.WriteLine(SerializerTool.Serialize(eA));

Console.ReadLine();


GenericEntities gE = new GenericEntities();

gE.Add(e1);
gE.Add(e2);
gE.Add(e3);

Console.WriteLine("Generics");
Console.WriteLine(SerializerTool.Serialize(eA));

Console.ReadLine();

}
}

Io che sono più o meno testardo provando questo codice non i sono accorto di grandi differenze,
tanto che l'xml risultante è uguale per tutti ...
Che cosa cambia quindi ? I tempi ? I pesi ? L'occupazione di memoria ?

Per List e Arry non ho scritto righe di codice per Collection ho dovuto implementare il metodo Add ( ma è specializzato solo per le Entity ) per Generics ho dovuto implementare
tutto o quasi ma posso riutilizzare il codice completamente per altri scopi...

Quindi a parità di risultati possiamo ancora una volta scegliere differenti modalità di implementazione.

mercoledì 10 novembre 2010

Replace case Insensitve ?

Ahi.. la string.Replace() accetta due parametri ma è accettabile ?? No direi proprio di no.

Effettivamente mi sono prodigato più volte nell'affrontare una Replace IgnoreCase, e in molti (troppi casi) ci si trova a dover affrontare utenti che non leggono il manuale (come tutti noi del resto) è grave, davvero grave quando è chi installa un applicazione e la configura a non leggere
le specifiche.

Quindi ci si trova a leggere elementi da un file di configurazione che hanno valori non consoni
a quel che ci si aspetta.

Capita quindi che utilizzando una Replace in un Template qualcosa non vada...

Tuttavia nel namespace System.Text c'e' RegularExpression (ammetto un mondo nuovo e bellissimo) ... Dove potete trovare questo gioiello.

Regex.Replace (Testo di partenza, Testo Da trovare, Testo Che sostituisce, RegexOptions)

E proprio questo RegexOptions (Enumerativo) contiene anche IgnoreCase.

Qualcuno dice un po lento ( ma se si tratta di poche occorrenze fa il suo sporco lavoro per bene)

Volendo nello splendido mondo di Regular Expression si potrebbe anche pensare a qualcosa
di più efficace... ma credo che possa già essere efficace così.

List.Sort( )

Decisamente ostico, ma di sicura utilità...
Imbattersi in un sort su elementi complessi non è sempre una cosa semplice, anzi il più delle volte siamo noi a dover implementare una logica di Sort.

Gia ma come fare ???

Eccovi un esempio completo e funzionante di come creare un sort

Create una console Application in C# e copiate interamente il codice.

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

namespace ListT_Sort
{
class Program
{
static void Main(string[] args)
{
UseHost uh = new UseHost();

uh.CreateHostList();

uh.SortBeforePrint();

Console.ReadLine();
}
}

public class Host
{
private string _HostName;
private IPAddress _HostIP;

public string HostName
{
get{return _HostName;}
set{_HostName = value;}
}

public IPAddress HostIP
{
get{return _HostIP;}
set{_HostIP = value;}
}

public Host( string Name, IPAddress IP)
{
_HostName = Name;
_HostIP = IP;
}


}

public class UseHost
{
private List Hosts = new List();

public void CreateHostList()
{
Hosts.Add(new Host("OfficePC", IPAddress.Parse("175.10.33.1")));
Hosts.Add(new Host("Localhost",IPAddress.Parse("127.0.0.1")));
Hosts.Add(new Host("HomePC",IPAddress.Parse("192.168.3.1")));
Hosts.Add(new Host("PortablePC",IPAddress.Parse("194.30.5.28")));
Hosts.Add(new Host("AbtServer", IPAddress.Parse("196.221.5.28")));
}

public void SortBeforePrint()
{
Hosts.Sort(CompareHosts);

for (int i =0; i< Hosts.Count; i++)
{
Console.WriteLine (Hosts[i].HostName);
}
}

public int CompareHosts(Host hp1, Host hp2)
{
if ((hp1 == null) && (hp2 == null))
{
return 0;
}

if ((hp1 == null) && (hp2 != null))
{
return -1;
}

if ((hp1 != null) && (hp2 == null))
{
return 1;
}

if (hp1.HostName == hp2.HostName)
{
return 0;
}

return String.CompareOrdinal(hp1.HostName, hp2.HostName);
}
}
}


Spiegazione pezzo per pezzo..

Questo è il tipo che noi abbiamo implementato o che abbiamo bisogno di implementare.
Si tratta di un tipo semplice tuttavia non implementa altre interfaccie ma solo due
campi.
Tuttavia già questa struttura è una buona base su cui studiare il sort.

public class Host
{
private string _HostName;
private IPAddress _HostIP;

public string HostName
{
get{return _HostName;}
set{_HostName = value;}
}

public IPAddress HostIP
{
get{return _HostIP;}
set{_HostIP = value;}
}

public Host( string Name, IPAddress IP)
{
_HostName = Name;
_HostIP = IP;
}
}

Ho implementato il costruttore solo per fare più in fretta...

Lista degli Host che dobbiamo Ordinare... messa giù un po a caso...

Hosts.Add(new Host("OfficePC", IPAddress.Parse("175.10.33.1")));
Hosts.Add(new Host("Localhost",IPAddress.Parse("127.0.0.1")));
Hosts.Add(new Host("HomePC",IPAddress.Parse("192.168.3.1")));
Hosts.Add(new Host("PortablePC",IPAddress.Parse("194.30.5.28")));
Hosts.Add(new Host("AbtServer", IPAddress.Parse("196.221.5.28")));


Chiamata al metodo di Sort ...
Hosts.Sort(CompareHosts);


Comparazione fra elementi...

if ((hp1 == null) && (hp2 == null))
{
return 0;
}

Gli elementi sono uguali ( e nulli )

if ((hp1 == null) && (hp2 != null))
{
return -1;
}

il secondo elemento è per forza maggiore il primo è null!!

if ((hp1 != null) && (hp2 == null))
{
return 1;
}

Il primo elemento è il maggiore ( vedi sopra)
if (hp1.HostName == hp2.HostName)
{
return 0;
}


Bene dato che il mio elemento di comparazione sono
i campi nome .. li confronto..
return String.CompareOrdinal(hp1.HostName, hp2.HostName);

Smart and Easy...

martedì 2 novembre 2010

DataTable.Select( Filter )

Giusto perchè sono sempre il primo a dimenticarsi le cose semplici... ecco una delle mille cosette che servono ma che ci si dimentica di utilizzare.

Quanto ci cosa una query in memoria ??? e costa di meno di una Query su Db ???

Come sempre tutto dipende da che cosa si deve fare anche se sono più che convinto che in molti casi caricarsi un centinaio di record in memoria non sia poi così oneroso (ad oggi).

In alcuni casi torna comodo, però saper effettuare una query anche in memoria..

in questo esempio ho creato una dataTable con 4 colonne, e ben poche righe, in questo modo
è più semplice seguire gli esempi.


DataTable dt = new DataTable("filteTest");
dt.Columns.Add("clnNome");
dt.Columns.Add("clnCognome");
dt.Columns.Add("clnNazionalita");
dt.Columns.Add("clnNote");


dt.Rows.Add(new object[] { "Valentino", "Rossi","i", "Motociclista" });
dt.Rows.Add(new object[] { "Lorenzo", "Jorge", "s", "Motociclista" });
dt.Rows.Add(new object[] { "Daniel", "Pedrosa","s", "Motociclista" });
dt.Rows.Add(new object[] { "Rolling", "Stoner","a", "Stunt man" });
dt.Rows.Add(new object[] { "Andrea", "Dovizioso","i", "Motociclista" });


DataRow[] drsMotociclisti = dt.Select("clnNote = 'Motociclista'");
Console.WriteLine( drsMotociclisti.Length.ToString() ); // scrive 4

DataRow[] drsItaliani = dt.Select("clnNazionalita = 'i'");
Console.WriteLine(drsItaliani.Length.ToString()); // scrive 2

DataRow[] drsMisti = dt.Select("clnNazionalita = 's' OR clnNazionalita ='i' ");
Console.WriteLine(drsMisti.Length.ToString()); // scrive 4

DataRow[] drsMisti = dt.Select("clnNazionalita = 'i' AND clnNote = 'Motociclista ");
Console.WriteLine(drsMisti.Length.ToString()); // scrive 2


ps. Non è una nota polemica, ma non ho proprio trovato esempi in cui far CADERE Stoner, tuttavia sono convinto che farlo sia già bravo senza il mio aiuto.