HOWTO: Order generic collections with LINQ

To order collections in LINQ you can use the extension method OrderBy(), which can be found in the static class Sytem.Linq.Enumerable. It can be used in all types of collections that implement the interface System.Collections.Generic.IEnumerable. The following example orders a list of Person objects by their age.


List persons = new List();

persons.Add(new Person("Peggy", "Bundy", 39));
persons.Add(new Person("Doug", "Heffernan", 34));
persons.Add(new Person("Tim", "Tailor", 41));
persons.Add(new Person("Homer", "Simpson", 34));
persons.Add(new Person("Al", "Bundy", 41));

persons = persons.OrderBy(person => person.Age).ToList();

Output:
Heffernan, Doug (34)
Simpson, Homer (34)
Bundy, Peggy (39)
Tailor, Tim (41)
Bundy, Al (41)

The person class is quite simple:


public class Person
{
    public int Age { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName;
        Age = age;
    }

    public override string ToString()
    {
        return string.Format("{0}, {1} ({2})", LastName, FirstName, Age);
    }
}



If you want to order the persons also by their last name you can use the extension method ThenBy(). It has to be appended at the end of the OrderBy() method.


persons = persons.OrderBy(person => person.Age).ThenBy(person => person.LastName).ToList();

Output:

Heffernan, Doug (34)
Simpson, Homer (34)
Bundy, Peggy (39)
Bundy, Al (41)
Tailor, Tim (41)

Mocken von Klasseninstanzen mit Rhino Mocks

Rhino Mocks lässt sich dazu nutzen, um in Unit Tests Klasseninstanzen zu faken, die nicht von einer abstrakten Klasse oder einem Interface abgeleitet sind. Dazu ein kleines simples Beispiel:


    public class Bl
    {
        public string GetStatus()
        {
            Funktionen funktionen = new Funktionen();

            if (funktionen.LangAndauerndeFunktion())
                return "OK";
            
            return "Nicht OK";
        }
    }

Die Funktion GetStatus erzeugt eine Instanz der Klasse Funktionen und ruft eine Methode auf, die einen boolschen Wert zurückgibt. Basierend darauf wird ein Text zurückgegeben (OK/Nicht OK). Die Klasse Funktionen ist folgendermaßen aufgebaut:


    public class Funktionen
    {
        public bool LangAndauerndeFunktion()
        {
            //Hier wird irgendwas performancelastiges ausgeführt
            //komplizierte Berechnungen, Datenbankzugriffe, etc...

            return true; //Rückgabe, damit das Projekt kompiliert werden kann
        }
    }

Um die Funktion GetStatus mit einem Unit Test abdecken zu können, sind folgende Änderungen nötig:

1. Die Funktion LangAndauerndeFunktion() virtual markieren, damit RhinoMocks diese überschreiben kann.


    public class Funktionen
    {
        public virtual bool LangAndauerndeFunktion()
        {
            //Hier wird irgendwas performancelastiges ausgeführt
            //komplizierte Berechnungen, Datenbankzugriffe, etc...

            return true; //Rückgabe, damit das Projekt kompiliert werden kann
        }
    }

2. Die Instanzierung der Klasse Funktionen in eine Factory-Methode verschieben. Die Methode muss protected virtual sein, um im Unit Test eine gefakte Instanz übergeben zu können.


    public class Bl
    {
        public string GetStatus()
        {
            Funktionen funktionen = GetFunktionenInstance();

            if (funktionen.LangAndauerndeFunktion())
                return "OK";
            
            return "Nicht OK";
        }

        protected virtual funktionen GetFunktionenInstance()
        {
            return new Funktionen();
        }
    }

Für die Erstellung der Unit Tests benötigt man nun eine Hilfsklasse, die von der zu testenden Klasse (in diesem Fall Bl) abgeleitet ist. Diese überschreibt die Funktion GetAusgelagerteFunktionen:


    public class BlTestHelper : Bl
    {
        public Funktionen FunktionenInstance { get; set; }
        protected override Funktionen GetFunktionen()
        {
            return FunktionenInstance ?? base.GetFunktionenInstance();
        }
    }

Die Unit Tests sehen für die GetStatus – Methode der zu testenden BL wie folgt aus:


    [TestFixture]
    public class BlTests
    {
        [Test]
        public void GetStatus_LangAndauerndeFunktionReturnsFalse_ReturnsNichtOk()
        {
            MockRepository mockRepository = new MockRepository();
            Funktionen funktionen = mockRepository.Stub<Funktionen>();

            using (mockRepository.Record())
            {
                SetupResult.For(funktionen.LangAndauerndeFunktion()).Return(false);
            }

            BlTestHelper helper = new BlTestHelper();
            helper.FunktionenInstance = funktionen;

            string status = helper.GetStatus();

            Assert.That(status.Equals("Nicht OK"));
        }

        [Test]
        public void GetStatus_LangAndauerndeFunktionReturnsTrue_ReturnsOk()
        {
            MockRepository mockRepository = new MockRepository();
            Funktionen funktionen = mockRepository.Stub<Funktionen>();

            using (mockRepository.Record())
            {
                SetupResult.For(fFunktionen.LangAndauerndeFunktion()).Return(true);
            }

            BlTestHelper helper = new BlTestHelper();
            helper.FunktionenInstance = funktionen;

            string status = helper.GetStatus();

            Assert.That(status.Equals("OK"));
        }

    }

Zu beachten ist, dass man in den Tests die BlTestHelper – Klasse instanziert und dieser den vom MockRepository erzeugten Stub übergibt. Die Testergebnisse zeigen, dass meine BL wie gewünscht reagiert:
Ergebnisse des Unit Tests

Setzen eines Properties per Reflection

Ab und an kann es nützlich sein, Properties einer Klasse per Reflection setzen zu können. Dazu ist lediglich folgender Code nötig:


public void SetProperty( string nameOfProperty, object value )
{
    PropertyInfo propertyInfo = GetType().GetProperty( nameOfProperty, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase );
            
    if( propertyInfo == null )
        throw new NullReferenceException( string.Format( "Die Eigenschaft {0} konnte nicht gefunden werden!", nameOfProperty ) );

    Type propertyType = propertyInfo.PropertyType;
    propertyInfo.SetValue( this, Convert.ChangeType(value, propertyType), null );
}

Beispiel:


public class Person
{
    public string Vorname { get; set; }
    public string Nachname { get; set; }

    public override string ToString()
    {
        return string.Format("{0}, {1}", Nachname, Vorname);
    }

    public void SetProperty( string nameOfProperty, object value )
    {
        PropertyInfo propertyInfo = GetType().GetProperty( nameOfProperty, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase );
            
        if( propertyInfo == null )
            throw new NullReferenceException( string.Format( "Die Eigenschaft {0} konnte nicht gefunden werden!", nameOfProperty ) );

        Type propertyType = propertyInfo.PropertyType;
        propertyInfo.SetValue( this, Convert.ChangeType(value, propertyType), null );
    }
}


class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        person.SetProperty("Vorname", "Thorsten");
        person.SetProperty("Nachname", "Vogt");
        Console.WriteLine(person); // Ausgabe: Vogt, Thorsten
    }
}

Prüfen ob eine Klasse ein bestimmtes Interface implementiert

Ab und an kann es vorkommen, dass man zur Laufzeit bestimmen muss, ob eine Klasse ein bestimmtes Interface implementiert. Dies läßt sich mit der Methode IsAssignableFrom() der Klasse System.Type realisieren:


public interface IMyInterface
{
    //Interface Code        
}

public class MyInterfaceImplementation : IMyInterface
{
    //Implementierung
}

public class AnotherClass
{ 
    //...
}

typeof(IMyInterface).IsAssignableFrom(typeof(AnotherClass)); //false
typeof(IMyInterface).IsAssignableFrom(typeof(MyInterfaceImplementation)); //true


Erweiterungsmethode: String.Like

Hier eine kleine Erweiterungsmethode, die ein SQL Like auf Strings ermöglicht:


public static bool Like( this string value, string pattern )
{
    string parsedPattern = "\\A" + Regex.Escape( pattern ).Replace( "\\*", ".*" ).Replace( "\\?", "." ) + "\\Z";

    Regex regex = new Regex(parsedPattern, RegexOptions.IgnoreCase);

    return regex.IsMatch(value);
}

Die Funktion eignet sich, wenn ich statt einer Linq-Abfrage einen Lamda-Ausdruck verwenden will/muss:


List<string> theSimpsons = new List<string>(){"Homer", "Bart", "Marge", "Lisa", "Maggie"};

Func<string, bool> matchCriteria = person => person.Like("*ar*");
Debug.WriteLine( "*ar*" );

foreach (string character in theSimpsons.Where(matchCriteria))
{
    Debug.WriteLine( character );
}

matchCriteria = person => person.Like( "M*i*" );
Debug.WriteLine( "M*i*" );
foreach( string character in theSimpsons.Where( matchCriteria ) )
{
    Debug.WriteLine( character );
}

matchCriteria = person => person.Like( "M*e" );
Debug.WriteLine( "M*e" );
foreach( string character in theSimpsons.Where( matchCriteria ) )
{
    Debug.WriteLine( character );
}

matchCriteria = person => person.Like( "*a*" );
Debug.WriteLine( "*a*" );
foreach( string character in theSimpsons.Where( matchCriteria ) )
{
    Debug.WriteLine( character );
}

matchCriteria = person => person.Like( "*a" );
Debug.WriteLine( "*a" );
foreach( string character in theSimpsons.Where( matchCriteria ) )
{
    Debug.WriteLine( character );
}


Ausgabe:
*ar*
Bart
Marge
M*i*
Maggie
M*e
Marge
Maggie
*a*
Bart
Marge
Lisa
Maggie
*a
Lisa

WHERE IN (…) Abfragen mit LINQ

Hier ein einfaches Beispiel, welches aus einer Liste von Büchern nur die Bücher von bestimmten Autoren findet:


List<Book> books = new List<Book>();
Book book;

book = new Book()
{
    Author = "Michael Moore",
    Title = "Stupid White Men",
    Price = 9.90M
};
books.Add(book);

book = new Book()
{
    Author = "Christian Nagel",
    Title = "C# 2008",
    Price = 59.99M
};
books.Add(book);

book = new Book()
{
    Author = "Robert C. Martin",
    Title = "Clean Code",
    Price = 19.90M
};
books.Add(book);

List<string> authorsToSearch = new List<string>(){"Michael Moore", "Robert C. Martin"};

books.Where(bookItem => authorsToSearch.Contains(bookItem.Author)).ToList().ForEach(Console.WriteLine);

Als Ausgabe erhält man hier nur die Bücher, deren Autor einem Author der Suchliste entspricht:

Michael Moore: Stupid White Men (9,90)
Robert C. Martin: Clean Code (19,90)

Ich habe in dem Beispiel den Where-Filter als Lambda eingesetzt, alternativ kann man die Suche natürlich auch direkt mit einer LINQ-Abfrage durchführen:


var booksFound = from bookItem in books
                        where authorsToSearch.Contains(bookItem.Author)
                        select bookItem;

Reflection und statische Klassen

Ich habe mich letztens mal mit dem Thema Reflection beschäftigt. Dabei kam zwangsläufig das Problem auf, dass ich irgendwie festellen musste, ob eine Klasse statisch ist oder nicht. Auf Nachfrage bei Google bin ich dann auf diesen Blogeintrag gestoßen, der sich mit genau diesem Problem beschäftigte:

http://dotneteers.net/blogs/divedeeper/archive/2008/08/04/QueryingStaticClasses.aspx

Windows Services: OnStart() debuggen

Einen Windows Service zu debuggen ist eigentlich recht einfach: Service starten, Visual Studio an den Prozess anhängen, fertig. Das funktioniert allerdings nicht ohne Weiteres bei der OnStart()-Methode, da diese beim Dienststart durchlaufen wird. Das Debugging kann hier auf zwei Arten erreicht werden:
1. Pausieren des Prozesses mittels Thread.Sleep()


        protected override void OnStart(string[] args)
        {
            Thread.Sleep(20000);
            Timer tTimer = new Timer(1000);
            tTimer.Elapsed += tTimer_Elapsed;
            tTimer.Start();
        }

2. Aufrufen des Debuggers mittels Debugger.Launch()


        protected override void OnStart(string[] args)
        {
            Debugger.Launch();
            Timer tTimer = new Timer(1000);
            tTimer.Elapsed += tTimer_Elapsed;
            tTimer.Start();
        }

Ich persönlich bevorzuge die 2. Methode, da man zum einen nicht erst warten muss, bis Thread.Sleep() beendet wird, zum anderen spart man sich das manuelle Anhängen an den Prozess. Der Aufruf von Debugger.Launch() sorgt dafür, dass man per Dialog eine neue Visual Studio Instanz öffnen kann, die dann zum Debuggen genutzt wird. Allerdings sollte man darauf achten, dass man den Aufruf nur dann tätigt, wenn man auch wirklich debuggen will. Dies kann beispielsweise per Kommandozeilenparameter durchgeführt werden.

Datentyp einer DataTable-Spalte ändern

Der Datentyp einer Spalte im DataTable lässt sich durch die DataType-Eigenschaft ermitteln oder festlegen.


DataTable t = new DataTable();
t.Columns.Add("Col1", typeof(string));
t.Columns["Col1"].DataType = typeof (Int32);

Allerdings ist das Setzen des Typs nur möglich, wenn das DataTable keine Daten enthält. Für ein gefülltes DataTable kann dies über ein zweites DataTable-Objekt, das per Clone() erstellt und mittels ImportRow() gefüllt wird, erreicht werden.


DataTable t = new DataTable();
t.Columns.Add("Col1", typeof (string));
for (int iCounter = 1; iCounter < 25; iCounter++)
{
  DataRow dRow = t.NewRow(); 
  dRow["Col1"] = iCounter.ToString();
  t.Rows.Add(dRow);
}
DataTable t2 = t.Clone();
t2.Columns["Col1"].DataType = typeof (Int32);
foreach (DataRow row in t.Rows)
{
  t2.ImportRow(row);
}