Mrz 182017
 

Vor ein paar Tage bin ich an der Arbeit auf ein interessantes Phänomen gestossen, dass mir so bisher noch nicht bewusst war. Wenn man die Math.Round() Methode von .NET verwendet, dann heisst das nicht automatisch, dass bei 1.5 auf 2 und bei 2.5 auf 3 aufgerundet wird. Ein kleines Beispielprogramm zeigt das Verhalten der Math.Round() Methode des .NET Frameworks:

Und das Ergebnis:

Komisch, irgendwie haben wir das in der Schule doch mal anders gelernt… Die Antwort ist aber ganz einfach, denn in der MSDN Dokumentation steht unter Math.Round(double):

Rundet einen Gleitkommawert mit doppelter Genauigkeit auf den nächsten ganzzahligen Wert.

Im englischen heisst dieses Verfahren „Bankers Rounding“ und hat den Vorteil, dass bei einer Verteilung von Werten das arithmetische Mittel der gerundeten Zahlen gleich dem arithmetischen Mittel der nicht gerundeten Zahlen ist. Um dennoch das von uns gewüschte Verhalten zu erhalten, ist Math.Round() überladen und man kann zusätzlich noch das MidpointRounding mit angeben. Im folgenden Beispiel sieht man dann das umgestellte Programm:

Ergebnis:

Das Problem ist jetzt nicht riesig, aber dennoch ist es ein Verhalten, dem man sich bewusst sein sollte, wenn man mathematische Berechnungen durchführt. In unseren Anwendungen hat es in wenigen Fällen zu abweichenden Ergebnissen geführt und die Math.Round() Methode hatte dabei niemand auf dem Schirm.

Mrz 022016
 

Wir alle bemühen uns performanten und möglichst effizienten Code zu schreiben und auch gegebenenfalls vorhandenen Legacy Code zu verbessern. Um seinen Code zu optimieren gilt die gute alte Regel – messen, messen und nochmal messen, denn nur so kann man die Engpässe vernünftig identifizieren, um danach gezielt eine Lösung zu suchen. Ich arbeite im Normalfall an dieser Stelle mit der guten alten Stopwatch, die man unter System.Diagnostics im .NET Framework findet.

Scott Hanselman hat in seinem Blog aber eine weitere, sehr elegante Möglichkeit vorgestellt, um Methodenaufrufe und Programmteile zu bewerten. Er verwendet dazu die Open Source Bibliothek BenchmarkDotNet, die man natürlich auch als NuGet Package bekommen kann. Fügt man sie einem Projekt hinzu, so kann man mittels dem Attribut Benchmark Methoden markieren, die man genauer betrachten möchte. Über den BenchmarkRunner kann man dann die Klasse mit den Attributen aufrufen.

Am besten sieht man das an einem kleinen Beispiel, das man so auch auf der GitHub Seite von BenchmarkDotNet findet. Die Idee hinter den Beispiel ist es, die Hashverfahren MD5 und SHA256 miteinander zu vergleichen. Wir erstellen also eine einfache Klasse, die ein Array mit Zufallswerten erzeugt und darauf mit dem Aufruf von zwei Methoden, die mit dem Benchmark Attribut markiert werden, sowohl den MD5 als auch den SHA256 laufen lassen:

In der Main Methode unserer Anwendung (oder in einem anderen Teil der Anwendung) starten wir dann mit

den Benchmark. Die Bibliothek führt jetzt den Benchmark auf den Methoden durch und das kann durchaus etwas dauern. Am Ende erhaltet ihr dann eine Zusammenfassung des Benchmarks, die bspw. so aussehen kann:

Im bin-Verzeichnis findet ihr außerdem noch wesentlich ausführlichere Ergebnisse des Benchmarks, so unter anderem auch Readme Dateien für die gängigsten Webdienste (bspw. GitHub und StackOverflow), aber auch CSV Dateien, die ihr weiter analysieren könnt. Natürlich kann man noch wesentlich mehr mit der Bibliothek testen (bspw. die unterschiedlichen JIT Varianten, Anzahl der Prozessoren, die .NET Runtime, etc.) oder auch die Ergebnisausgabe an eigene Vorgaben anpassen.
Was verwendet ihr denn so für das Benchmarking von Methoden und Programmteilen? Auch Stopwatch? Die BenchmarkDotNet Bibliothek? Etwas anderes? Würde mich über einen Kommentar von euch freuen :-)!

Jan 232015
 

Beim Schreiben von Unittests bin ich mal wieder darüber gestolpert, dass jemand speziell für die Unittests Getter und Setter angelegt hat, da er auf die privaten Variablen der Klasse nicht zugreifen konnte. Im Prinzip hat er damit für seinen Unittest die internen Variablen dann über den Zugriffsmodifizierer public dann doch wieder sichtbar gemacht, wenn auch nur indirekt. Das ist so natürlich nicht gewollt, denn sonst hätte man gleich den Zugriff auf die internen Variablen erlauben können. Vielleicht noch kurz zur Erklärung: unsere Unittests sind immer in eigenständige Assemblies ausgelagert, sodass wir von Außen auf die zu testenden Klassen zugreifen müssen. Das macht auch Sinn, da die Unittests in dem Kompilat nicht enthalten sein sollen. Wie kann man das Problem also lösen?

Das .NET Framework bietet dafür das Attribut InternalsVisibleTo aus dem Namespace System.Runtime.CompilerServices an. Um nun die internal Methoden, Variablen und Properties freizugeben, wird das Attribut in die AssemblyInfo.cs des zu testenden Projekts eingefügt.

Danach kann man mit dem im InternalsVisibleTo-Attribut angegeben Assembly seine Unittests auf den Klassen durchführen ohne alles Zugriffsmodifizierer auf public zu setzen.

Solltet ihr eure Assemblies signieren, muss das einzufügende Attribut um den Public Key des zugreifenden Assemblies erweitert werden. Zusätzlich muss außerdem das zugreifende Assembly signiert werden. Der Eintrag in der AssemblyInfo.cs sieht dann so aus:

Das ist natürlich nur eine Herangehensweise, aber – wie ich finde – eine doch recht elegante. Wie macht ihr das in euren Unittests? Habt ihr eine ähnliche Vorgehensweise oder schreibt ihr einfach gar keine ;-)?

Dez 082014
 

Bei der Entwicklung von Unittests für mein privates Windows Store und Windows Phone Projekt bin ich bei der Konvertierung der alten Unittests für die Portable Class Library (PCL), die in dem Projekt verwendet wird, darüber gestolpert, dass auf einmal das „ExpectedException“ Attribut nicht mehr gefunden wird. Dieses Attribut verwendete man in den Unittests, um Tests zu kennzeichnen, die eine Exception werfen müssen. So richtig sauber war das allerdings irgendwie noch nie, da man eigentlich die einzelnen Bedingungen mittels „Assert“ geprüft hat. Es ist also nur konsequent, dass das Attribut mittlerweile entfernt wurde und durch eine entsprechende Methode in der Assert-Klasse ersetzt wurde. Folgendes kleines Beispiel zeigt die Verwendung der Methode „ThrowsException“:

Simpel, oder? Hat mich allerdings trotzdem etwas Zeit gekostet, da ich mit dieser Änderung erst mal nicht gerechnet habe.

Nov 132014
 

Ja! Richtig gelesen: Microsoft hat sich dazu entschlossen das.NET zukuünftig als Open Source Software zur Verfügung zu stellen und das nicht unter irgendeiner dubiosen Lizenz, sondern unter der sehr freizügigen MIT-Lizenz. Der Quellcode wird außerdem auf GitHub verwaltet und Pull-Requests werden auch ermöglicht. Jeder kann also in Zukunft am .NET Kern mitarbeiten. Dieser Schritt hat sich bereits schon länger abgezeichnet. Man hat die .NET Foundation gegründet, die sich in Zukunft mit der Weiterentwicklung von .NET befassen wird, die neue Compiler Plattform „Roslyn“ wurde direkt als Open Source freigegeben, F# ist Open Source und der Sourcecode des .NET Frameworks ist unter http://referencesource.microsoft.com auch schon länger einsehbar.
Neben der Open Source Strategie sieht man, dass .NET auf immer mehr Plattformen läuft. Dank Xamarins Mono ist .NET nämlich fast überall zu Hause – sei es iOS, Android, Linux, Mac OS X, den Raspberry Pi, die Nintendo Wii, die Playstation, die Xbox sowieso – um nur mal einige zu nennen. Mittlerweile wird auch der Cross-Platform Ansatz auch innerhalb Visual Studio immer besser unterstützt, d.h. die Entwicklung für Android, iOS, Windows Phone und Desktop Apps wird immer einfacher.
Für mich steht seit einiger Zeit schon fest, dass .NET irgendwie zum neuen Java geworden ist. Zwar gilt der alte Leitspruch von Java ,“Write once, run everywhere“, nicht in .NET, da man immer noch plattformabhängige Teile implementieren muss, aber man kann große Teile der Business Logik bereits auslagern und muss nur noch wenig neu implementieren und, was meiner Meinung nach viel wichtiger ist, warten. Die Sprache ist immer noch lebendig, d.h. sie wird fortwährend weiterentwickelt und hat sich dadurch bereits einen Vorsprung gegenüber dem langsamen Java Community Process erarbeiten können (man denke mal an die lange Hängepartie mit den Lambda-Ausdrücken :-/).
Ich freue mich jedenfalls über die neue Offenheit von Microsoft und bin gespannt, wie es weiter geht. Vielleicht wird es ja irgendwann mal ein Open Source Windows geben ;-)?

Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen