String Concatenation in C# Benchmark

datesabato 31 ottobre 2009 alle 16.12  - posted by Manuel Scapolan in C#

Ci sono diversi modi per concatenare una stringa in C# : con String.Concat,  utilizzando uno StringBuilder, con String.Format oppure ricorrendo all'overloading dell'operatore +. Spinto dalla curiosità di sapere quale di questi modi fosse il più performante ho realizzato un semplice test:

using System;
using System.Text;
using System.Diagnostics;
 
public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("String concatenation benchmark");
      Console.WriteLine("------------------------------");
      Console.WriteLine("Plus operator: " + StringPlusOperatorTest());
      Console.WriteLine("String.Format: " + StringFormatTest());
      Console.WriteLine("String.Concat: " + StringConcatTest());
      Console.WriteLine("StringBuilder: " + StringBuilderTest());
      Console.ReadLine();
   }
   
   private static string StringPlusOperatorTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
      result = i + " Nel mezzo del cammin di nostra vita, " 
            + "mi ritrovai per una selva oscura" 
            + " ché la diritta via era smarrita.";
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }
 
   private static string StringFormatTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
         result = String.Format("{0}{1}{2}{3}", 
            i, " Nel mezzo del cammin di nostra vita, ", 
            "mi ritrovai per una selva oscura", 
            " ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }
 
   private static string StringConcatTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
         result = String.Concat(i, 
            " Nel mezzo del cammin di nostra vita, ", 
            "mi ritrovai per una selva oscura", 
            " ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }
 
   private static string StringBuilderTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      for (int i = 0; i < 10000000; i++)
      {
         StringBuilder sb = new StringBuilder();
         sb.Append(i);
         sb.Append(" Nel mezzo del cammin di nostra vita, ");
         sb.Append("mi ritrovai per una selva oscura");
         sb.Append(" ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }

Il test consiste nel concatenare tre stringhe più un contatore. Data la semplicità dell'operazione per avere dei risultati misurabili ho dovuto inserire l'operazione in un ciclo for. Dai risultati visibili nell'immagine qui sotto si può notare come l'operatore + sia il più veloce seguito dal metodo String.Concat e a grande distanza dagli altri due metodi...

 

String Concatenation Benchmark

Se però consideriamo una concatenazione con più stringhe (42 per la precisione) otteniamo i risultati visibili nell'immagine sottostante. L'operatore + è ancora il migliore, ma il metodo String.Concat peggiora notevolemente forse per il numero cospicuo di parametri.

 

String Concatenation Benchmark

Per quanto possa essere misurabile e percepita dall'utente la differenza di performance questo test conferma una banalità, usare String.Concat per la concatenazione di stringhe e String.Format per la formattazione. :-)

tagsTags: ,

Impostare la pagina di default con MonoRail Routing HttpModule

datevenerdì 30 ottobre 2009 alle 21.30  - posted by Manuel Scapolan in Castle Project

Oggi ho avuto l'occasione di utilizzare il Routing di MonoRail per risolvere un problema da tempo in sospeso, ovvero chiamare l'action di default quando nell'indirizzo viene specificato solo il nome del controller. Ad esempio se digitiamo mysite.com/admin MonoRail deve essere in grado di richiamare mysite.com/admin/default.rails.
La prima cosa da fare è creare nella root del sito la cartella admin con all'interno una pagina Default.aspx senza code-behind. In questo modo ASP.NET riscriverà la chiamata a mysite.com/admin con l'indirizzo mysite.com/admin/Default.aspx. In secondo luogo dobbiamo registrare nel web.config l'HttpModule di Routing:

<httpModules>
 <!-- il modulo di routing deve precedere quello di monorail -->
 <add name="routing" type="Castle.MonoRail.Framework.RoutingModule,
    Castle.MonoRail.Framework" />
 <add name="monorail" type="Castle...EngineContextModule,
    Castle.MonoRail.Framework"/>
</httpModules>

A questo punto possiamo dichiarare delle regole di routing specificando con le regular expression quali indirizzi considerare e come eseguirne la riscrittura:

<monorail useWindsorIntegration="true">
   <viewEngine viewPathRoot="Views" 
      customEngine="Castle.MonoRail...NVelocity.NVelocityViewEngine, 
      Castle.MonoRail.Framework.Views.NVelocity"/>
   <routing>
      <rule>
         <pattern>(\b/\w+)/?Default.aspx$</pattern>
         <replace><![CDATA[ $1/default.rails ]]></replace>
      </rule>
      <rule>
         <pattern>(/Default.aspx)</pattern>
         <replace><![CDATA[ /home/default.rails ]]></replace>
      </rule>
   </routing>
</monorail>

Nell'esempio sono state registrare due regole, nella prima vengono considerati tutti gli indirizzi che iniziano con il carattere / seguito da almeno un carattere alfanumerico e che terminano con un carattere / e la stringa Default.aspx, questi indirizzi vengono riscritti prendendo la parte prima del Default.aspx aggiungendovi /default.rails. La seconda regola invece ci permette di intercettare le chiamate alla pagina Default.aspx che si trova nella root del sito e che con la logica della prima regola porterebbe ad un controller vuoto e di conseguenza ad una bella eccezione. In questo caso l'indirizzo viene sostituito con /home/default.rails.

Nota: Per utilizzare questa tecnica è necessario creare una Default.aspx con relativa cartella per ogni controller dell'applicazione o meglio per i controller che necessitano di una pagina di default.

Le migliori shortcuts di Visual Studio 2008

datemartedì 27 ottobre 2009 alle 21.22  - posted by Manuel Scapolan in Tips and Tricks

Le shortcuts sono sicuramente la via più breve e semplice per migliorare la produttività. Ecco un elenco delle migliori tra quelle a disposizione con Visual Studio 2008:

  • [CTRL] + [SHIFT] + [B] -> esegue il build della solution
  • [CTRL] + [SHIFT] + [S] -> salva tutti i file aperti
  • [CTRL] + [I] -> attiva la funzione di ricerca incrementale. Dopo aver premuto tale combinazione digitare la chiave di ricerca ed una volta completata la chiave spostarsi in avanti sempre con CTRL + I ed indietro con CTRL + SHIFT + I
  • [F5] e [SHIFT] + [F5] -> il primo fa partire il debug l'altro lo interrompe
  • [SHIFT] + [F9] -> pone la variabile selezionata dal cursore sotto "Quick Watch" 
  • [CTRL] + [SHIFT] + [Space] -> posizionandosi all'interno della chiamata di un metodo permette di vedere in un tooltip la lista di parametri richiesta dal metodo
  • [CTRL] + [.] -> apre la finestra smart tag utile in caso di inserimento di uno using per un tipo sconosciuto
  • ([CTRL] + [K]) + [F]-> esegue la formattazione della selezione corrente
  • ([CTRL] + [K]) + [C] e ([CTRL] + [K]) + [U] -> il primo commenta le righe selezionate, l'altro esegue l'operazione inversa
  • [ALT] + [SHIFT] + [Enter] -> attiva la modalità FULL SCREEN, ripremere la stessa combinazione di tasti per disattivare la modalità
  • ([CTRL] + [\]) + [D] -> apre la finestra Code Definition per il tipo sotto cursore
  • [CTRL] + [SHIFT] + [F] -> permette di eseguire la funzione di ricerca nei file del progetto
  • [SHIFT] + [Canc] -> cancella la riga corrente salvandola negli appunti
  • [CTRL] + [-] e [CTRL] + [SHIFT] + [-] -> sposta il cursore nella posizione successiva o precedente
  • [F12] -> esegue il "Go to definition"

Tra le più curiose ci sono invece:

  • [CTRL] + [ì] -> se mi posiziono su una parentesi di un blocco di codice ed eseguo questa combinazione di tasti il cursore si posiziona sull'altra parentesi che delimita il blocco
  • [CTRL] + [SHIFT] + [ì] -> se mi posiziono su una parentesi di un blocco di codice con questa combinazione seleziono tutto il blocco di codice
  • [CTRL] + []] -> seleziona il pezzo di codice compreso tra il cursore e l'ultima posizione di modifica
  • [CTRL] + [T] ->inverte le lettere ai lati del cursore

 E se non ci bastano dalla finestra Tools > Options > Keyboard ne possiamo creare di nuove:
 

Custom Shortcuts

Come indicizzare una proprietà di un tipo non primitivo in Lucene.Net con un FieldBridge di NHibernate.Search

datedomenica 25 ottobre 2009 alle 21.02  - posted by Manuel Scapolan in NHibernate | Lucene.NET

Può essere utile a volte indicizzare con Lucene.Net una proprietà di un oggetto che non sia una stringa o un tipo primitivo, pensiamo ad esempio alla lista di categorie di un prodotto. Per casi come questo e laddove l'accesso ai dati viene fatto con NHibernate posso raggiungere il risultato desiderato utilizzando un FieldBridge di NHibernate.Search ed un po' di reflection:

public class PropertyBridge 
      : ITwoWayStringBridge, IParameterizedBridge
{
  private Type _type;
  private string _propertyName;
  
  public string ObjectToString(object obj)
  {
    StringBuilder sb = new StringBuilder();
    PropertyReflector pr = new PropertyReflector();
    if (obj.GetType().IsGenericType && 
      typeof(PersistentGenericBag<>).IsAssignableFrom(
          obj.GetType().GetGenericTypeDefinition()))
    {
      IEnumerable enumerable = obj as IEnumerable;
      if (enumerable != null)
      {
        IEnumerator enumerator = enumerable.GetEnumerator();
  
        while (enumerator.MoveNext())
        {
          object current = enumerator.Current;
          if(current!=null)
          {
            sb.Append(pr.GetValue(current,_propertyName) + " ");
          }
        }
        return sb.ToString();
      }
    }
    else
    {
      sb.Append(pr.GetValue(obj,_propertyName));
    }
    return sb.ToString();
  }
  
  public void SetParameterValues(object[] parameters)
  {
    Object classType = parameters[0];
    if (classType != null)
      this._type = (Type)classType;
    _propertyName = parameters[1].ToString();
  }
 
  public object StringToObject(string stringValue)
  {
    throw new NotImplementedException();
  }
}

Il FieldBridge permette a NHibernate.Search di indicizzare con Lucene il contenuto di una proprietà qualora non fosse coerente utilizzare il metodo ToString() (quasi mai per i tipi non primitivi). Analizzando il codice sopra riportato si può notare come vengano passati al FieldBridge due parametri: il tipo di oggetto ed il nome della proprietà da indicizzare (righe 38-44). Con questi due parametri ed utilizzando l'utility PropertyReflector (classe di utilità scritta da Guy Mahieu per fare "deep-reflection" di proprietà) viene recuperato il valore da salvare nell'indice di Lucene. Il FieldBridge in oggetto riesce ad indicizzare sia oggetti singoli (righe 31-34) sia collezioni verificandone il tipo ed utilizzando l'interfaccia IEnumerator (righe 11-30). Qui sotto possiamo notare l'utilizzo dell'attributo per una proprietà di tipo IList<T>.

[FieldBridge(typeof(PropertyBridge), 
    new object[] { typeof(Category), "CategoryID" })]
public virtual IList<Category> Categories { get; set; }

Nota: il PropertyBridge visto in questo esempio nasce da una esigenza specifica e per questo motivo non ricopre tutte le casistiche possibili.

About me

manuel scapolanSono un consulente informatico. Nel 2004 terminati gli studi in Ingegneria Informatica (1° livello), ho iniziato come freelance collaborando con una ditta di consulenza informatica ed una agenzia di marketing e comunicazione nello sviluppo di applicazioni web. Attualmente divido il lavoro di sviluppatore e progettista web con attività di formazione nel settore della programmazione.
View Manuel Scapolan's profile on LinkedIn

Follow me on Follow manuelscapolan on Twitter

Calendario


<<  agosto 2010  >>
lumamegivesado
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

Disclaimer

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati mediante:
creative commons
Attribuzione: Non commerciale
Condividi allo stesso modo. R.2.5

Books (a bit more about my library)

Domain Driven Design - Eric Evans Applying Domain-Driven Design and Patterns - Jimmy Nilsson Refactoring to Patterns - Joshua Kerievsky Design Patterns -  Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides Code Complete Second Edition - Steve McConnell Patterns of Enterprise Application Architecture - Martin Fowler Agile Principles, Patterns, and Practices in C# - Robert C. Martin xUnit Test Patterns - Gerard Meszaros Refactoring - Martin Fowler CLR via C# Second Edition - Jeffrey Richter Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries - Krzysztof Cwalina, Brad Abrams Don't make me think! - Steve Krug Bulletproof Ajax - Jeremy Keith

Manuel Scapolan Copyright © 2007 - 2010 - Tutti i diritti riservati - Powered by BlogEngine.NET 1.5.0.7 - silk icons by famfamfam - Time CET