Kategorien

Navigation

Feeds/Meta

Blog RSS Feed
Kommentare RSS Feed

Manuel Josupeit-Walter - XING Profil
Manuel Josupeit-Walter - Amazon Wunschliste
Manuel Josupeit-Walter - XMPP (Jabber)
Manuel Josupeit-Walter - ICQ
Manuel Josupeit-Walter - Skype

Bloggeramt.de
BlogAlm
Add to Technorati Favorites

SpamPoison

josupeit.com > Weblog


Fame But Insane Konzert mit Le Mur

Datum:   13.12.2007, 16:02 Uhr
Kategorie:   Musik Feed dieser Kategorie abonnieren
Kommentare:   0

Hey Leute,

heute mal Werbung in eigener Sache: Fame But Insane spielt am 08. März 2008 zusammen mit Le Mur in Dortmund Scharnhorst. Wenn Ihr also Zeit und Lust habt, kommt einfach vorbei. Wir freu'n uns auf jeden Fall. Nähere Infos gibts bei Fame But Insane oder sicher auch bei Le Mur.

Möbel zu verkaufen

Datum:   12.12.2007, 12:29 Uhr
Kategorie:   Privat Feed dieser Kategorie abonnieren
Kommentare:   7

Um einer Freundin von mir ein wenig unter die Arme zu greifen, hier einmal offiziell:

Illustration Schrank Illustration Deckenleuchte Illustration Gerahmtes Bild
Schlafzimmerschrank Deckenleuchte Gerahmtes Bild

stehen ab sofort zwecks Umzug zum Verkauf und da die gute Frau auch noch wahnsinnig ordungsliebend ist, sind die Klamotten dementsprechend super in Schuss :-). Die Handyfotos sind nicht gerade gut, aber immerhin.

Bei Interesse lass' doch einfach einen Kommentar da, ich stelle dann den Kontakt her. Die Preise sind natürlich verhandlungssache, der Schrank liegt glaube ich so bei 200 Euro.

Implementierung eines Singleton in C#

Datum:   21.11.2007, 09:59 Uhr
Kategorie:   C# und .NET im Allgemeinen Feed dieser Kategorie abonnieren
Kommentare:   2

Es gibt Situationen, in denen man als Entwickler sicherstellen möchte, dass von einer Klasse nur ein Objekt instanziiert werden kann. Für diesen Anwendungsfalls gibt es bereits einen Lösungsansatz: Das Singleton-Pattern1. Das Prinzip dieses Ansatzes ist recht simpel und beruht unter anderem auf der Nutzung statischer Felder und Methoden. Diese sogenannten statischen Member einer Klasse unterscheiden sich von den Instanzmembern in sofern, als dass sie genutzt werden können, ohne explizit ein Objekt zu instanziieren.

Am Beispiel C# (Mircosoft .NET Framework 2.0) möchte ich an dieser Stelle in zwei Schritten eine Art systemweiten Singleton implementieren, dieser Artikel befasst sich allerdings zunächst mit dem ersten Schritt: der Implementierung des herkömmlichen Singleton. Die Erweiterung einer bestehenden Klasse zum Singleton funktioniert in C# wie folgt:


public class Beispiel
{
  /*
   * Dieses statische Feld hält unsere Instanz der
   * Klasse
   */
  private static Beispiel _Instanz;
 
  /*
   * Konstruktor der Klasse wird über den Zugriffsmodifizierer
   * "private" geschützt, um eine Instanziierung der Klasse von
   * außen zu unterbinden.
   */
  private Beispiel()
  {
    // TODO: Implementieren Sie Ihren Konstruktor hier
  }
 
  /*
   * Statische Methode, die die Instanz der Klasse zurück gibt.
   */
  public static Beispiel GetInstance()
  {
   if (_Instanz == null)
    _Instanz = new Beispiel();

   return _Instanz;
  }
}

Anhand dieses Beispiels sehen Sie, dass nur eine Instanz der Klasse Beispiel erzeugt wird und zwar über die statische Methode GetInstance():


public static void main(string[] args)
{
 Beispiel BeispielInstanz = Beispiel.GetInstance();
}

Der direkte Aufruf von BeispielInstanz = new Beispiel(); ist unzulässig, da der Konstruktor der Klasse privat ist.

Um auf einfachem Wege ihren Quelltext wiederverwenden zu können, lagern wir nun diesen Code in eine Bibliothek aus. Dieses Vorhaben allerdings erscheint nur auf den ersten Blick einfach: über Vererbung. Allerdings kann aus der Basisklasse nicht ohne Weiteres auf die abgeleitete Klasse zugegriffen werden, dies widerspräche auch dem Sinn von Vererbung, so dass folgendes Vorhaben nicht funktioniert:


public abstract class Singleton
{
  private static Singleton _Instanz;
 
  private Singleton()
  {
    // TODO: Implementieren Sie Ihren Konstruktor hier
  }
 
  public static Singleton GetInstance()
  {
   if (_Instanz == null)
     // Hier müsste die Kindklasse instanziiert werden
    _Instanz = new ?();

   return _Instanz;
  }
}

Abgesehen von diesem Problem kann eine abgeleitete Klasse so nicht instanziiert werden, da die Basisklasse durch die Verwendung des Schlüsselwortes private den Konstruktor schützt, ein Zugriff auf diesen Konstruktor durch Reflektion über die Basisklasse ist allerdings auch nicht möglich2.

Das Zauberwort an dieser Stelle lautet Generika3, denn generische Klassen erlauben es dem Entwickler, Typdefinitionen für ganze Klassen oder Methoden offen zu lassen. Wir entwickeln unser Singleton-Pattern also weiter zu einer statischen Klasse, also einer Klasse, die selbst nicht instanziiert werden kann, die aber unsere Singleton-Objekte verwaltet. Diese Klasse soll den Namen SingletonProvider bekommen. Damit künftig einfach entschieden werden kann, ob es sich um eine neue Instanz handelt oder nicht, erweitern wir gleich unsere Methode GetInstance() um einen boolschen Wert:


using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

public static class SingletonProvider
{
  /*
   * Die Hashtabelle Selfs hält unsere Instanz-
   * objekte intern im Speicher.
   */

  private static Hashtable Selfs = new Hashtable();
 
  // Dieses Objekt wird zur Threadsynchronisation verwendet
  private static object Lock     = new Object();

  public static T GetInstance<T>(out bool New)
    where T: new()
  {
    // Threadsynchronisation
    lock (Lock) {
      /*
       * Überprüfen, ob bereits eine Instanz
       * des generischen Typen T existiert.
       * Als Schlüssel für die Hashtabelle verwenden
       * wir die GUID des Typen.
       */

      if (Selfs.ContainsKey(typeof(T).GUID))
      {
        // Instanz existiert bereits
        New = false;
        return (T)Selfs[typeof(T).GUID];
      }

      // Neue Instanz erstellen
      Selfs.Add(typeof(T).GUID, new T());
      New = true;
     
      return (T)Selfs[typeof(T).GUID];
    }
  }
}

Durch diese Klasse können nun auf einfachem Wege Singleton-Objekte erzeugt werden:


public static void main(string[] args)
{
 bool neueInstanz;
 Beispiel MeinBeispiel = SingletonProvider.GetInstance<Beispiel>(out neueInstanz);
}

Die Variable MeinBeispiel enthält nun eine neue Instanz der Klasse Beispiel, die Variable neueInstanz ist wahr, falls der SingletonProvider ein neues Objekt erzeugt hat. Der Typ Beispiel ist genau der "Lückenfüller" für unseren generischen Typen T im Beispiel oben. Einzige Bedingung: Es muss sich um eine Klasse handeln, die einen parameterlosen, öffentlichen Konstruktor besitzt (siehe where T: new()). Dies allerdings widerspricht wiederum dem Singleton-Gedanken, denn nun kann wieder eine Instanz der Klasse von Außen erzeugt werden: MeinBeispiel = new Beispiel(); Der Singleton ist somit ausgehebelt.

Wir modifizieren an dieser Stelle unseren SingletonProvider, so dass ausschließlich Klassen mit geschützten Konstruktoren verwendet werden können. Außerdem überladen wir unsere GetInstance-Methode der Einfachheit halber wie folgt:


using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

public static class SingletonProvider
{
  private static Hashtable Selfs = new Hashtable();
  private static object Lock     = new Object();

  public static T GetInstance<T>(out bool New)
    where T: class // Jede Klasse ist erlaubt
  {
    // Threadsynchronisation
    lock (Lock) {
      if (Selfs.ContainsKey(typeof(T).GUID))
      {
        // Instanz existiert bereits
        New = false;
        return (T)Selfs[typeof(T).GUID];
      }

      // Neue Instanz über Reflektion erstellen
      ConstructorInfo ctorInfo;
     
      // Geschützte Konstruktoren auslesen
      ctorInfo = typeof(T).GetConstructor(
                  BindingFlags.NonPublic |
                  BindingFlags.Instance,
                  null,
                  Type.EmptyTypes,
                  null
                );
               
      // Konstruktor ohne Parameter aufrufen
      T _Instanz = (T)ctorInfo.Invoke(new object[] { });
     
      // Instanz der Hashtabelle zuführen
      Selfs.Add(typeof(T).GUID, _Instanz);
      New = true;
     
      return (T)Selfs[typeof(T).GUID];
    }
  }
 
  /*
   * Für den Fall, dass es egal ist,
   * ob es sich um ein neues Objekt handelt
   */

  public static T GetInstance<T>()
    where T: class
  {
    bool _Trash;
    return GetInstance<T>(out _Trash);
  }
}

Nun wird der private parameterlose Konstruktor zur Instanziierung verwendet. Als nächstes verbieten wir ausdrücklich öffentliche Konstruktoren und schmeißen andernfalls einen Fehler:


using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

public static class SingletonProvider
{
  private static Hashtable Selfs = new Hashtable();
  private static object Lock     = new Object();

  public static T GetInstance<T>(out bool New)
    where T: class // Jede Klasse ist erlaubt
  {
    // Auf öffentlichen Konstruktor prüfen
    ConstructorInfo checkCtor = (typeof(T)).GetConstructor(Type.EmptyTypes);
   
    /*
     * Falls es einen solchen Konstruktor gibt,
     * schmeißen wir einen Fehler, da es dem
     * Charakter eines Singleton widerspricht.
     */

    if (checkCtor != null)
      throw new InvalidOperationException("Singleton means that you don't have any public constructors");

    // Threadsynchronisation
    lock (Lock) {
      if (Selfs.ContainsKey(typeof(T).GUID))
      {
        // Instanz existiert bereits
        New = false;
        return (T)Selfs[typeof(T).GUID];
      }

      // Neue Instanz über Reflektion erstellen
      ConstructorInfo ctorInfo;
     
      // Geschützte Konstruktoren auslesen
      ctorInfo = typeof(T).GetConstructor(
                  BindingFlags.NonPublic |
                  BindingFlags.Instance,
                  null,
                  Type.EmptyTypes,
                  null
                );
               
      // Konstruktor ohne Parameter aufrufen
      T _Instanz = (T)ctorInfo.Invoke(new object[] { });
     
      // Instanz der Hashtabelle zuführen
      Selfs.Add(typeof(T).GUID, _Instanz);
      New = true;
     
      return (T)Selfs[typeof(T).GUID];
    }
  }
 
  public static T GetInstance<T>()
    where T: class
  {
    bool _Trash;
    return GetInstance<T>(out _Trash);
  }
}

Mit Hilfe der obigen Implementierung der SingletonProvider-Klasse lassen sich nun beliebige Singleton-Objekte verwalten:


public class Beispiel
{

 private Beispiel()
 {
  Console.WriteLine("Klasse instanziiert");
 }
 
 public static void main(string[] args)
 {
  Beispiel MeinBeispiel  = SingletonProvider<Beispiel>.GetInstance();
  Beispiel MeinBeispiel2 = SingletonProvider<Beispiel>.GetInstance();
 }
}

Dieses Beispiel erzeugt auf der Konsole einmalig die Ausgabe "Klasse instanziiert", da der erste Aufruf von GetInstance() eine Instanz erzeugt. Der zweite Aufruf hingegen liefert ganz im Sinne des Singleton das selbe Objekt. Eine Instanz von Außen über MeinBeispiel = new Beispiel(); ist durch den geschützten Konstruktor übrigens nicht mehr möglich.

Möchte man nun eine Klasse schreiben, um andere Klassen von dieser "Singleton-Basis" erben zu lassen, bedienen wir uns der oben bereits implementierten Klasse SingletonProvider, der Singleton selbst soll hier allerdings nicht instanziiert werden und ist deshalb abstrakt:


public abstract class SingletonBase<T>
  where T: SingletonBase<T>
{
  public static T GetInstance(out bool New)
  {
    return SingletonProvider.GetInstance<T>(out New);
  }
 
  public static T GetInstance()
  {
    bool _Trash;
    return GetInstance(out _Trash);
  }
}

Da, wie oben bereits gesagt, die Elternklasse allerdings nicht auf die Kindklasse schließen kann, werwenden wir für die Anweisung where T: SingletonBase<T>, um den Typen zu "ermitteln". Dies ist zwar in gewisser Hinsicht eine Redundanz, da eigentlich bereits durch die Vererbung klar ist, dass eine Instanz von "Beispiel" erzeugt werden soll, leider gibt es meiner Ansicht nach aber derzeit keine wesentlich elegantere Lösung dieses Problems. Das .NET Framework 3.5 lässt allerdings bereits heute auf schönere Ansätze hoffen...


public sealed class Beispiel : SingletonBase<Beispiel>
{
    private Beispiel()
    {
     // Konstruktor
    }
}

Instanzen der Klasse können nun einfach via Beispiel.GetInstance() geholt werden, eine eigene Instanziierung durch Verwendung des Schlüsselwortes new() ist nicht mehr möglich. Ein Haken allerdings bleibt: Die Klasse sollte versiegelt sein, so dass von ihr nicht weiter geerbt werden kann, denn


class GeerbtesBeispiel : Beispiel
{ }

bietet nun auch die statische Methode GetInstance(), die allerdings nach wie vor die Basisklasse Beispiel instanziiert, nicht jedoch GeerbtesBeispiel. 

Damit nun dieser Artikel nicht noch länger wird, als er bisher schon ist, möchte ich dieses Beispiel beim nächsten Mal zu einem systemweiten Singleton ausbauen. Mit Hilfe dieser Methode lässt sich beispielsweise einfach realisieren, dass eine Anwendung nur einmal gestartet werden kann und jeder weitere Programmstart das bereits geöffnete Fenster in den Vordergrund holt. Dazu allerdings erst beim nächsten Mal mehr.

Abschließend bleibt mir eigentlich nur noch zu sagen, dass es sich bei diesem Artikel lediglich um ein Beispiel einer Möglichkeit der Umsetzung handelt. Es gibt noch unzählige weitere Implementierungen des Singleton, sehen Sie es also als eine Art Inspiration für Ihre Projekte, ich hoffe ich konnte Ihnen jedoch ein wenig bei der Lösung Ihres Problemes weiterhelfen.


GPLv3
1 Singleton (Entwurfsmuster): Wikipedia
2 Type.GetConstructor-Methode: Microsoft
3 Generische Typen: Wikipedia

 


Siehe auch:
Sprachelemente von C-Sharp (Wikipedia)

Männer sind primitiv, aber glücklich

Datum:   12.11.2007, 16:17 Uhr
Kategorie:   Privat Feed dieser Kategorie abonnieren
Kommentare:   1

Die Antwort auf die Frage, wieso Frauen nicht zugeben können, wenn Sie Deinen Hammer genommen haben, kann Mario in seinem aktuellen Programm "Männer sind primitiv, aber glücklich" auch nicht beantworten. Wohl aber zeigt er auf seine - wie immer - urkomische Berliner Art und Weise, wie man seine Freundin mit Flaschendrehen in den Wahnsinn treibt und animiert das Publikum dazu, Frau Müller zum Diktat zu rufen.

Diesen Samstag waren Gina und ich zum ersten Mal zu Gast bei einer von Marios Live-Shows in Oberhausen. Nachdem ich zu meinem letzten Geburtstag die DVD des vorigen Programmes "Männer sind Schweine, Frauen aber auch" geschenkt bekommen habe, stand der Entschluss bereits fest: Beim nächsten Mal bin ich dabei! Leider dachten das offensichtlich auch ein paar tausend andere Menschen, so dass die nächste Show, die nicht ausverkauft und zugleich in der Nähe war, leider fast ein Jahr auf sich warten ließ. Aber das Warten hat sich wirklich gelohnt: Die Hütte war brechend voll und es hat mordsmäßig viel Spaß gemacht. Ich kann jedem empfehlen, selbst live dabei zu sein. Allerdings solltet ihr früh buchen, denn es ist nicht leicht sich über einen so langen Zeitraum aller Gags zu entziehen: Ich durfte fast ein Jahr die CD nicht hören und habe jeden meiner Freunde abgewürgt, der begonnen habt, mir die Witze schon vorher zu erzählen. Vielen Dank jedenfalls, dass es zumindest einigermaßen geklappt hat...

Zum Schluss noch zwei Dinge: Bitte schenkt mir weder zu Geburtstag noch Weihnachten die aktuelle DVD, die hab ich mir nämlich direkt im Anschluss an die Show am Fanshop gekauft und zweitens: Menne, wenn Deine Freundin keinen Ostdeutschen Dialekt hat... Harr harr harr... Viel Spaß!

min-height im Internet Explorer

Datum:   26.10.2007, 14:56 Uhr
Kategorie:   HTML, CSS und Web Feed dieser Kategorie abonnieren
Kommentare:   2

Dass ich den Internet Explorer, zumindest in Versionen vor 7 nicht mag, ist für meine Arbeitskollegen kein Geheimnis und wenn man betrachtet, wie wenig sich Microsoft bei der Entwicklung dieses Browsers an geltende Standards vom W3C hält, ist dies sicherlich auch kein Wunder. An dieser Stelle aufzuzählen sind beispielsweise der 3-Pixel Fehler, die prägnante Miturheberschaft am Quirks-Mode oder die fehlerhafte Berechnung von Element-Dimensionen in Zusammenhang mit Innenabständen, von nicht implementierten CSS Attributen, wie min-width oder min-height einmal ganz abgesehen.

Im Job ist es teils eine wahre Qual, als letzten Schritt in der Umsetzung einer Webseite mit CSS Hacks (die das Stylesheet natürlich nicht valide machen) oder Conditional Comments das Layout den Fehlern des Internet Explorers anzupassen. Für alle Leidensgenossen möchte ich an dieser Stelle künftig Tipps und Kniffe beschreiben, die einem das Leben hinsichtlich dieser und anderer Probleme hoffentlich ein wenig leichter machen.

Das CSS-Attribut "min-height" beispielsweise wird vom IE leider nicht unterstützt, kann allerdings simuliert werden, möchte man auf oben angeführte CSS-Hacks oder Conditional Comments verzichten. Dies funktioniert auf einfachem Wege durch folgende Angaben im Stylesheet:

height: auto !important; /* Wird von modernen Browsern interpretiert */
height: 100%;            /* Für den IE: wie min-height */
min-height: 100%;        /* min-height für alle anderen Browser */

Diese Zeilen funktionieren durch eine fehlerhafte Interpretation der Angabe !important, die validen Browsern mitteilt, dass die Angabe "auto" bezüglich der Element-Höhe des Wertes "100%" vorgezogen wird, sprich, das Element soll bei übergroßem Inhalt automatisch wachsen. Obwohl das Attribut height im eigentlichen Sinne eine Höhe festlegt, lässt der IE dennoch eine dynamische Vergrößerung des Bereiches zu, sollte der Inhalt wachsen. height wird demnach vom Internet Explorer generell als min-height interpretiert. In diesem Sinne existiert die Angabe min-height sowieso nur für Browser, die CSS zumindest in dieser Hinsicht valide interpretieren, die Angabe height: auto !important setzt nur die 100%-ige Höhenangabe ausser Kraft.

An dieser Stelle sei generell noch einmal auf SelfHTML hingewiesen, denn dort lassen sich viele Attribute nachschlagen. Informationen bezüglich Conditional Comments und CSS-Hacks werden dort auch sehr gut erklärt.


[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]