# Tuesday, August 26, 2008

?? Operator in C#

Wer hätte das gedacht; In der C#-Spezifikation habe ich bereits das ein oder andere Mal herumgestöbert. Dabei ist mir aber glatt der Null-Koaleszenz-Operator ?? durch die Lappen gegangen. Wer ihn noch nicht kennt, sollte ihn sich einmal anschauen. Es lohnt sich auf jeden Fall.

Wo ich es her habe: BlaBlubBlog
Wo es sonst nach was dazu zu lesen gibt: Norbert Eder
Wo man es brauchen kann:
In der nachfolgenden Funktion wird durch den Null-Koaleszenz-Operator sichergestellt, dass die Klasse test in der Methode Main auf jeden Fall ungleich null ist (auf Stil und Schönheit wurde übrigens in diesem Beispiel kein Wert gelegt).
namespace ConsoleApplication1
{
    using System;

    class Program
    {
        static void Main( string[] args )
        {
            TestClass test = TestClass.CreateClass( ) ?? new TestClass( );
        }

        public class TestClass
        {
            public bool IsValid { get; private set; }

            public TestClass( )
            {
            }

            public static TestClass CreateClass( )
            {
                if ( new Random( ).Next( 1 ) == 0 )
                {
                    TestClass result = new TestClass( );
                    result.IsValid = true;
                    return result;
                }
                return null;
            }
        }
    }
}

Tuesday, August 26, 2008 9:09:39 PM (W. Europe Standard Time, UTC+01:00) #    Comments [2] | Trackback
# Tuesday, July 22, 2008

Spartanisch Programmieren - von Stefan Lieser

Stefan Lieser schreibt in seinem Blog, er wäre ein Freund des spartanischen Programmierens. Ich kann mich ihm dort nicht anschließen, da ich lieber Code schreibe, der sich lesen lässt; Variablen bekommen Namen, die auch ein Außenstehender versteht, Code wird kommentiert, es wird mit Freizeilen zur Strukturierung gearbeitet etc. Aber das ist, wie Stefan bereits schrieb, eine persönliche Einstellung. Wenn sie nicht durch Implementierungskonventionen erzwungen oder verboten wird.

Weshalb ich mich jedoch aufgefordert fühle, auf seinen Blogpost zu antworten, ist sein Fast-Exit-Beispiel. Um eine große Verschachtelungstiefe zu vermeiden, schreibt Stefan lieber viele Exits in einer Funktion, statt seinen Code ordentlich zu strukturieren. Zuerst ein schlechtes Beispiel (von Stefan ebenfalls als schlecht angesehen):
public void DoSomething() {
  if (a) {
    if (b) {
      if (c) {
        DoItRealy();
      }
    }
  }
}
Nun seine Verbesserung (Stichwort Fast-Exit), mit der ich noch immer nicht einverstanden bin:
public void DoSomething() {
  if (!a) {
    return;
  }
  if (!b) {
    return;
  }
  if (!c) {
    return;
  }

  DoItRealy();
}

Und nun zwei Arten, die ich persönlich den beiden Vorangegangenen (nicht uneingeschränkt, aber meistens) vorziehen würde:
public void DoSomething() {
  if ( ( a )
    && ( b )
    && ( c ) )
  {
    DoItRealy();
  }
}

public void DoSomething() {
  if (!a) 
  {
    Log("Not a");
  }
  else if (!b)
  {
    Log("Not b");
  }
  else if (!c)
  {
    Log("Not c");
  }
  else
  {
    Log("All requirements complied.");
    DoItRealy();
  }
}

Tuesday, July 22, 2008 6:01:54 PM (W. Europe Standard Time, UTC+01:00) #    Comments [1] | Trackback
# Wednesday, May 07, 2008

Powershell TCP Listener

The project I'm currently working on is an embedded device without any graphical interface capability. The only ways to get some information out is the NIC or a serial port. There is also a CAN-Bus interface, but as far as my company developed the device it is better to not base our debugging capabilities on a potentially buggy part of the system. Out first debug out was implemented as a serial output tracer. As the day comes closer that out hardware prototypes will arrive, the higher the need to port the tracing over to the NIC as far as the final hardware won't have a serial port on it.
So last week the network tracer was check in into source control. Now, how to read these information?
Windows ships with Hyper Terminal. But this isn't very comfortable and you manually have to reestablish a lost connection. In my today's lunch break I wrote a small powershell script that listens to the network socket. At the moment I'm porting it to C# to add some more features.

But here is the first part, a small and simple powershell script to listen to a network socket. But please let me clarify that this is code snippet is NOT the way code. It was a fast hack to get it running. There is no error handling and ressources are not freed gracefully as it has to be terminated with ctrl + c. In clear words: This is a sample on how to receive data from a network socket.

$socket = new-object System.Net.Sockets.TcpClient("172.16.170.123", 9950)
if($socket -eq $null) { return; }
$stream = $socket.GetStream()
$buffer = new-object System.Byte[] $socket.ReceiveBufferSize
$encoding = new-object System.Text.AsciiEncoding

while($true)
{
   if($stream.DataAvailable)
   {
      $read = $stream.Read($buffer, 0, $socket.ReceiveBufferSize)  
      write-host -n ($encoding.GetString($buffer, 0, $read))
   }
}

Wednesday, May 07, 2008 8:47:07 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Friday, April 18, 2008

Excel: Zellen verbinden per Shortcut

Ich musste gerade einige Zellen in Excel verbinden. Da mir das ewige Markieren - Rechtsklick - Zellen Formatieren - Zellen verbinden zu langsam war, habe ich nach einem Shortcut für diese Aktion gesucht. Leider bringt Excel so etwas nicht mit. Aber mit einem kleinen Macro kann man die Funktionalität nachrüsten:

Diese Makro wechselt nach der Zuweisung einer Tastenkombination den Status von mehreren Zellen von Nicht verbunden zu Verbunden und wieder zurück.
Sub Makro2()
    With Selection
        .HorizontalAlignment = xlGeneral
        .VerticalAlignment = xlBottom
        .WrapText = False
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = Not .MergeCells
    End With
End Sub

Friday, April 18, 2008 8:56:58 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Wednesday, April 09, 2008

Duff's Device

Da ich momentan eher mit C beschäftige, dort allerdings noch ein paar Fragen offen waren, hatte ich heute ein Code Review mit einem "alten Hasen". Dabei gab es eine Menge zu lernen. Als ich später mit meinem PM (der auch aus der C/C++-Welt stammt) das Review besprach, zeigt er mir einen netten kleinen Codeschnippsel: Duff's Device. Ich lasse das hier einmal ohne Erklärung stehen.
n = (anzahl + 3) / 4;
 
switch(anzahl % 4) {
    case 0:        do { ziel[stelle] = quelle[stelle]; stelle++;
    case 3:             ziel[stelle] = quelle[stelle]; stelle++;
    case 2:             ziel[stelle] = quelle[stelle]; stelle++;
    case 1:             ziel[stelle] = quelle[stelle]; stelle++;
                   } while(--n > 0);
}
Für meine C#-Augen war das ja gar nichts. Fallthrough im Switch-Statement. Brrr. Wenn das der Compiler sehen würde ;) Aber C ist eben etwas ganz anderes.

Wednesday, April 09, 2008 8:29:20 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Monday, April 07, 2008

String auf ASCII-Reinheit prüfen

Momentan liegt mein beruflicher Schwerpunkt eher auf der Programmiersprache C im Embedded Umfeld. Da dies jedoch nicht meine präferierte Sprache ist und außerdem die Arbeit (Webserverprogrammierung, CGI-Funktionen, etc) auf Grund der Vielzahl von ähnlichen CGI-Funktionen ein bisschen nach Automatisierung riecht, habe ich begonnen, einen Codegenerator zu schreiben.
Ein paar Worte zur Erklärung. Wir haben eine Anwendung mit zentraler Pseudodatenbank, die alle Programmteile als Quelle und Senke nutzen. Ca. 80% der Datenpunkte sollen per Web-Frontend editierbar sein. Um den Programmierer des Web-Frontends nicht mit den Interna des Microcontrollers zu belasten, stellen wir die Datenpunkte über CGI-Funktionen bereit. Somit muss für jeden Datenpunkt eine ähnlichlautende Zugriffsfunktion in C erstellt werden. Lediglich der Datentyp ändert sich. Die Pflege der Datenpunkte erfolgt in einer Excel-Datei, die auch externen Firmen zur Verfügung gestellt wird.
Da es sich bei dem generierten Code um C-Code handelt und die eingesetzte Entwicklungsumgebung keine Quelltexte in Unicode verarbeiten kann, muss ASCII-Code generiert werden. C# verarbeitet jedoch 2 Byte breite Chars und schreibt liebend gern Unicode. Dies wäre an sich kein Problem, da man einem StreamWriter ja über dessen öffentliche Eigenschaft Encoding die Codierung der Daten vorgeben kann. Jedoch sind, warum auch immer, in den Bezeichnern der Datenpunkte Umlaute vorhanden. Diese können jedoch nicht einfach so in ASCII konvertiert werden, da sie dort nicht definiert sind. So kam schnell der Gedanke nach einem eigenen Konverter oder Filter auf.
Aber wie?

Möglichkeit 1 - Regular Expression Match
System.Text.RegularExpressions.Regex regex = 
     new System.Text.RegularExpressions.Regex( "[^\x00-\x7F]" );
 if ( regex.IsMatch( testString ) )
 {
     //Nicht-ASCII-Zeichen gefunden
 }
Mit dieser Regular Expression werden alle Zeichen gefunden, deren Byte-Repräsentation nicht im Bereich 00 bis 7F liegt. Man könnte nun im If-Block ein paar Methoden zur Ersetzung von beispielsweise 'ä' einsetzen. Allerdings werden dann nur diese Zeichen ersetzt, alle anderen müssen anderweitig behandelt werden. Dadurch wird der Programmablauf inkonsistent.
Alternativ könnten diese Zeichen nicht weiter beachtet werden. Dies würde dann entsprechende Lücken in der Ausgabe hinterlassen.
Wird der If-Block jedoch nicht angesprungen, ist der String garantiert frei von Nicht-ASCII-Zeichen.

Möglichkeit 2 - Regular Expression Grouping
Ändert man den regulären Ausdruck von oben ein wenig ab, kann man die gefundenen Zeichen gruppieren. Dies ermöglicht es, eine Match-Collection zu verwenden, die weitergehende Möglichkeiten bietet. Die Syntax für des regulären Ausdrucks für die Gruppierung wäre:
System.Text.RegularExpressions.Regex regex = 
    new System.Text.RegularExpressions.Regex( "(^\x00-\x7F)" );
System.Text.RegularExpressions.MatchCollection matches =
    regex.Matches( testString );
foreach ( System.Text.RegularExpressions.Match match in matches )
{
    //Nicht-ASCII-Zeichen-Gruppe gefunden
}
Dabei stellt das Objekt Match eine ganze Reihe nützlicher Funktionen bereit, so zum Beispiel die Position des Matches im Ursprungs-String oder die Länge des Matches. Es werden nämlich mit dieser Möglichkeit auch Gruppen wie im Beispiel "Hallööö Welt" die Gruppe "ööö" als ein zusammenhängender Treffer erkannt.

Möglichkeit 3 - Die Klasse Encoding
Die Klasse Encoding stellt verschiedene Möglichkeiten bereit, um mit Zeichen und Zeichenketten zu hantieren. Bei dem oben dargestellten Problem war dies mein erster Anlaufpunkt. Jedoch bin ich nach einigen Monaten C-Programmierung hier einem falschen Pferd aufgesessen :). Man beachte nachfolgende Zeile C#-Code und komme bitte nicht auf die Idee, dies irgendwo zu verwenden:
Encoding.ASCII.GetString( (byte[])testString, 0, testString.Length );
Die Methode GetString der Klasse Encoding.ASCII erwartet als ersten Parameter ein Byte-Array. Was würde man also in C machen? Richtig. Wie oben geschrieben, castet man seine Zeichenkette, eigentlich ja nur ein Char-Array in ein Byte-Array. Die Datentypen sind ja jeweils 1 Byte lang. 1 Byte? Ein Char in C#? Und da steckt der Fehler. In C# ist ein Char 2 Byte lang. Stichwort Unicode. Glücklicherweise meckert dies bereits der Compiler an.
Wie dem auch sei. Der Versuch mündete schließlich in folgendem Qullcode:
string testString = "Halööö Welt. Hähähäh!!!";
byte[] byteArray = Encoding.ASCII.GetBytes( testString );
Console.WriteLine( Encoding.ASCII.GetString( byteArray, 0, byteArray.Length ) );
Dieser Codeschnippsel spuckt dann, wie erwartet, einen ASCII-String aus: Hall??? Welt. H?H?H?!!! Wer damit leben kann...

Fazit
Glücklicher Weise übermittelte mir plötzlich ein Kollege die frohe Botschaft, dass die Bezeichner in den nächsten Tagen auf englische Bezeichner umgestellt werden. Also Umlaute ade. Das ist mir in dieser Situation gar nicht unpassend, da mir keine triviale Lösung für das Problem der Konvertierung eines Unicode-Strings in einen ASCII-String bekannt ist. Schließlich müssen einige Dinge beachtet werden, zum Beispiel die CurrentCulture, da wahrscheinlich ein ö in Deutschland einfach durch oe ersetzt werden kann. Ob das im türkischen ebenso möglich ist, weiß ich nicht.

Dieser Beitrag soll zum einen Anregungen geben, wie die Lösung eines solchen Problems angegangen werden kann. Zum anderen ist es ein Aufruf: Falls jemand dieses Problem schon einmal lösen musste, wäre ich (wahrscheinlich nicht ausschließlich) sehr dankbar, seinen Weg kennenzulernen.

Monday, April 07, 2008 8:02:49 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback