Das Megos .NET-Weblog

31. Januar 2009

IntelliSense und Erweiterungen von Klassen

Gespeichert unter: Keine Kategorie — Schlagworte: , — René Brunner @ 14:44

IntelliSense in Visual Studio ist eine wunderbare Sache, die das Programmieren ungemein erleichtert. Eigentlich sollte heutzutage niemand mehr in einer Umgebung programmieren müssen, wo kein in etwa gleichwertiges Feature zur Verfügung steht. Trotzdem sahen wir ein ernstzunehmendes Problem damit, als wir hier in der Megos ernsthaft damit begannen, unsere neues Programmierwerkzeug Triton in C# zu implementieren.

IntelliSense scheint seine Listen immer stur alphabetisch zu sortieren und immer alles aufzulisten, ohne Filtermöglichkeiten. Das kann dan zu einem Problem werden, wenn man Klassen erweitert, die bereits eine Menge Members haben, und dann in der IntelliSense-Liste seine „eigenen“ Members (d.h. diejenigen der Erweiterung) kaum mehr findet. Je nach Art der Klassen benötigt man beim Implementieren bevorzugt eben diese eigenen Members, was das Ganze dann etwas mühsam macht.

Unsere Überlegungen zeigten uns, dass sich die Sache zuspitzt, wenn man Klassen für den Datenbank-Zugriff generiert, wo für jede Kolonne in einer Tabelle eine Property definiert wird, die sich dann zu all den Members der Zugriffs-Basisklasse gesellt und unter diesen irgendwie unterzugehen droht, obwohl sie doch zum eigentlichen „Witz“ der generierten Klasse gehört.

Man kann das bereits bei Visual-Studio-eigenen typed datasets beobachten: Eine Tabellen-Zugriffs-Klasse wird von System.Data.TypedTableBase abgeleitet, einer Klasse mit geschätzten etwa 100 Members. Eine Kolonne TitelKurs wird zu einer Property namens TitelKursColumn und wird von IntelliSense unter T eingeordnet; eine Kolonne WährungsKurs wird zu WährungsKursColumn und taucht dann in der Liste unter W und damit an einem ganz anderen Ort auf. Dieses Verhalten verunmöglicht es praktisch, sich per IntelliSense einen schnellen Überblick über alle Kolonnen zu verschaffen – aber wo ausser da soll denn dieser Überblick herkommen?

Es war schnell klar, dass es bei Visual Studio und IntelliSense, so wie jetzt implementiert, nur ein einziges „Rädchen“ gibt, an dem man überhaupt drehen kann, wenn man dieses Problem irgendwie lösen will: Will man Members zusammen sehen in einer IntelliSense-Liste, so müssen sie eben entsprechend heissen, d.h. alle mit irgendeinem Präfix beginnen.

Sie werden als geneigter Leser vielleicht schon ahnen, dass dieser Blog-Eintrag hier geradewegs auf ein Dilemma zumarschiert: Von Namenspräfixen wird in .NET und C# eigentlich abgeraten; verwendet man sie trotzdem, stecken einen gewisse Leute schnell einmal in die Schublade „Ewiggestrige“, die reserviert ist für Leute, die von ihren alten Gewohnheiten nicht lassen können und auch nicht verstanden haben, dass man heutzutage nur noch „natürliche“ Namen vergibt, weil man – eben gerade durch Features moderner IDEs wie z.B. IntelliSense – nicht mehr darauf angewiesen ist, vom Namen eines Dings irgendwelche Meta-Information ablesen zu können.

Aber wie gesagt, hier geht es nicht darum, sondern um eine Lösung für ein kleines, aber sehr lästiges Problem mit IntelliSense.

Wir sahen das Ganze als Wahl zwischen zwei Übeln: 1) einen Teil der Namen mit Hilfe von Präfixen verunstalten, aber damit den Nutzen von IntelliSense aufwerten, oder 2) den Empfehlungen und der Mehrheit der C#-Programmierer folgen, aber sich mit Situationen abfinden, in denen IntelliSense wenig hilft, obwohl es gerade da sehr nützlich wäre.

Nach einigem Hin und Her entschieden wir uns für das Übel 1). Wir wählten z.B. für die Properties unserer eigenen Klassen in Triton den Einbuchstaben-Präfix z, weil eine Abklärung ergab, dass nur wenige .NET-Klassen bereits Properties haben, mit mit Z beginnen, und damit diese Properties nicht nur zusammen angezeigt werden in einer IntelliSense-Liste, sondern auch noch herausstechen.

Seit dieser Entscheidung haben wir eine rechte Menge Code gemäss diesen Präfix-Konventionen erzeugt, und es ist eine erste Beurteilung des Erreichten möglich. Der gewünschte Effekt bei IntelliSense hat sich eingestellt: Man behält so tatsächlich ohne Probleme den Überblick über die eigenen Dinge im Gegensatz zu den „fremden“ Dingen des Frameworks. Aber hübsch sieht es irgendwie nicht aus, und eine richtige Gewöhnung an unsere mit Präfixen dekorierten Namen will sich eigentlich auch nicht einstellen.

Für jemanden, der sich im .NET-Framework wirklich gut auskennt, gäbe es vielleicht eine Wahlmöglichkeit 3), welche das Dilemma umgeht: ein Add-In programmieren, welches neben der IntelliSense-Liste eine zweite, entsprechend eingeschränkte Liste implementiert. Aber ganz soweit sind wir in der Megos noch nicht…

22. November 2008

Mehrfachvererbung

Gespeichert unter: Keine Kategorie — Schlagworte: , , — René Brunner @ 16:00

Manchmal wird man ziemlich unverhofft mit einem Problem konfrontiert, das man schon lange kannte, aber von dem man nicht ernsthaft erwartete, ihm jemals zu begegnen. So ging es mir mit der Mehrfachvererbung.

Ohne mich je genauer damit zu beschäftigen, war ich bisher der Meinung, es sei schon in Ordnung, dass viele Programmiersprachen Mehrfachvererbung nicht unterstützen, denn auf der einen Seite waren mir mögliche und vor allem sinnvolle Anwendungen nicht klar, aber auf der anderen Seite möglicher Ärger wie z.B. schwer verständliche Programme sehr wohl.

Umso mehr überrascht es mich, dass ich mir beim Design unseres neuen .NET-basierten Programmierwerkzeugs Triton jetzt genau diese Mehrfachvererbung wünsche, sie aber natürlich in C# nicht bekomme!

Worum geht es? Ich möchte die Funktionalität von Controls für Forms erweitern, notabene die von Standard-Controls wie TextBox, CheckBox, Button usw. Ich brauche z.B. Unterstützung für eine „schlaue“ Validierung von Eingabewerten, wo ich zwischen „validiert in Bezug auf den aktuellen Wert des Controls selbst“ und „validiert auch unter Berücksichtigung gegenseitiger Abhängigkeiten“ unterscheiden möchte.

So entsteht der Bedarf, eine neue Angabe ValidationState bei den Controls unterzubringen, am liebsten gleich zusammen mit einigen Methoden, welche das Validieren unterstützen.

Natürlich steht es mir frei, von allen schätzungsweise etwa 10 System.Windows.Forms.Control-Klassen, die ich brauche, neue Klassen abzuleiten und bei allen diesen eine Property ValidationState einzuführen, aber so erhalte ich natürlich 10 verschiedene Klassen mit 10 völlig unabhängigen und inkompatiblen Properties.

Ideal wäre natürlich, die Basisklasse Control selbst um eine Property ValidationState plus zugehörigen Code erweitern zu können, aber zumindest mit C# 3.0 wäre der einzige Weg hierzu eine Modifikation des Framework-Source-Codes und eine Neukompilation, was für mich natürlich nicht in Frage kommt. Auch eine abgeschwächte Variante, bei der ich Control unverändert lasse, aber eine eigene Klasse SmartValidationControl oder so quasi in den Baum der Vererbung „einfügen“ darf, hat dieselben nicht erfüllbaren technischen Voraussetzungen.

Und hier kommt jetzt die Mehrfachvererbung ins Spiel: 10 von diversen Controls abgeleitete Klassen wären in Ordnung, wenn sie ausser vom jeweiligen Control auch noch von einer zweiten Klasse SmartValidationControl ableiten dürften!

Was wäre mit 10 UserControl-Klassen mit einer gemeinsamen Basisklasse und mit dem jeweiligen eigentlichen Control als Kind? Dieser Ansatz ist natürlich möglich, artet aber aus in eine umfangreiche Fleissaufgabe, eine Menge Properties der Controls „durchzuschlaufen“, damit sie im Designer als Properties des Containers für Änderungen zur Verfügung stehen.

Schlussendlich bin ich beim folgendem Ansatz gelandet, den ich als das „geringste Übel“ ansehe: Ich leite 10 Klassen von 10 verschiedenen Controls ab, gebe aber allen diesen Klassen ein bestimmtes Interface, das ich dann eben 10 Mal implementieren muss.

Bei meinen Abklärungen über Mehrfachvererbung per Google bin ich über ein paar Seiten gestolpert, die sich vielleicht lohnen weiterzugeben:

Hier erläutert jemand aus dem C#-Team von Microsoft, dass die CLR selbst offenbar einen Weg bietet für Mehrfachvererbung, damit zumindest im Prinzip die Möglichkeit besteht, .NET-basierte Compiler zu bauen für Sprachen, welche Mehrfachvererbung umfassen.

hier hat jemand Mehrfachvererbung in C# so sehr vermisst, dass er sich eine „Simulation“ derselben ausgedacht hat, die recht trickreich mit Operatoren für implizite Typumwandlungen arbeitet. (Ich finde das Resultat insgesamt gesehen trotzdem ernüchternd.)

Und hier findet man schliesslich ein schon etwas älteres Interview mit dem „C# Compiler Program Manager“ bei Microsoft, dem man die offizielle Haltung von Microsoft zum Thema entnehmen kann.

Anhand der vielen Treffer, die Anfragen nach multiple inheritance oder auch spezifisch c# multiple inheritance in Google produzieren, kann man sehen, dass es sich offenbar um eine Sache handelt, die immer wieder aufkommt. Es wäre interessant zu wissen, ob es keine elegante Lösung des Problems geben kann, weil das Universum eben ist wie es ist, oder ob einfach noch niemand die geniale Idee gehabt hat…

27. September 2008

Die Geschichte vom unscharfen Text

Gespeichert unter: Keine Kategorie — Schlagworte: , — René Brunner @ 15:44

Windows Presentation Foundation, kurz WPF, ist eine relativ neue Technologie von Microsoft, um für .NET-Programme grafisch anspruchsvolle Benutzeroberflächen zu bauen. Ein wie ich finde sehr gelungenes Beispiel einer mit Hilfe von WPF erstellten kommerziellen Applikation (also etwas in der Art, wie die Megos auch Software anbietet), findet man hier.

Es gibt bei WPF allerdings ein Problem, und je nach dem, wen man fragt, sogar ein ziemlich gewichtiges: WPF verwendet für sämtliche Textausgaben Anti-Aliasing, mit dem Resultat, dass Text mehr oder weniger unscharf wird, je nach Monitor, Bildschirmauflösung, Schrift und dem Sehvermögen des Betrachters. Ich habe hier zwei WPF-Buttons mit ihren Beschriftungen in fast unfairer Weise vergrössert, damit man das Phänomen in seiner ganzen Pracht sieht (in Originalgrösse sehen die Buttons brauchbar aus):

WPF Anti-Aliasing

Ein weiteres Beispiel findet man hier.

Anti-Aliasing bei Textausgabe muss nicht schlecht sein, und schon seit einiger Zeit leistet die ClearType-Fonttechnologie auf Windows XP z.B. auf gewissen Notebook-Displays gute Dienste. Aber: Man kann es bei WPF nicht ausschalten, auch in der neuesten Framework-Version 3.5 nicht, und es ist eine von ClearType unabhängige, unterschiedliche Implementation, die offenbar nicht immer gleich gut ist.

Wie man dieser Diskussion in einem MSDN-Forum entnehmen kann, bitten gewisse Entwickler Microsoft nun schon seit über 2 Jahren inständig darum, man möge doch einen Schalter einführen, um die Sache abzuschalten. Passiert ist offenbar in der ganzen Zeit – ausser einigen Erklärungsversuchen von Microsoft und Zusicherungen, man nähme das Problem ernst – nichts.

Es handelt sich um eine Sache, die vielschichtiger ist, als man nach dem ersten Blick meint. Die in der WPF verwendete Technologie ermöglicht es, Buchstaben quasi genauer als nur auf Pixel genau zu positionieren, und das kann wichtig sein bei dynamischen Layout- und Grössenänderungen, wie sie WPF unterstützen möchte.

Man kann auch relativ schnell mit einem Argument von Microsoft einig gehen, dass Anti-Aliasing auf Monitoren mit hoher Pixeldichte (Anzahl Pixel pro Distanz), also z.B. nicht mit den üblichen 96 Pixels pro Inch, sondern 200 oder noch mehr, wunderbar aussieht.

Man könnte sich trotzdem relativ einfach auf den Standpunkt stellen, dass etwaige „Nebenwirkungen“ des Abschaltens des Anti-Aliasing voll auf den Schultern des Programmierers lasten, welcher abschaltet, und ich denke, die Leute in der erwähnten Diskussion wären damit auch sofort einverstanden. Trotzdem hatte Microsoft bisher kein Einsehen.

Solche Geschichten faszinieren mich oft, weil ich mich unweigerlich frage, was wohl jeweils die Geschichte hinter der Geschichte ist. Ich spekuliere gerne über die „Wahrheit“, die oft ziemlich wenig mit Technik und ziemlich viel mit Psychologie zu tun haben dürfte. Es muss fast mehr dran sein als einfach nur ein „Informatik-Problem“, sonst wäre die Sache schon längst ausgestanden.

Darf ich also mal ein bisschen spekulieren, und ein paar Verschwörungstheorien über den nach wie vor unscharfen WPF-Text in die Welt setzen? (Und es sind Spekulationen, ich weiss nicht mehr als Sie!)

  • Irgend ein hohes Tier bei Microsoft ist Fan von Anti-Aliasing, will von Kritik einfach nichts wissen und ist so mächtig, dass er oder sie nicht überstimmt werden kann.
  • Microsoft möchte Druck ausüben auf die Hersteller von LCD-Panels, damit diese tatsächlich dazu übergehen, in Richtung hoher Pixeldichten zu entwickeln, was sie im Moment eher nicht tun – die Displays werden meistens einfach nur grösser.
  • Irgend jemand bei Microsoft mit viel Einfluss und Reputation hat sich am Anfang dermassen stark gemacht für Anti-Aliasing, dass er oder sie jetzt unmöglich eine Fehleinschätzung zugeben kann.
  • Das ungeliebte Anti-Aliasing bleibt drin sozusagen als Bestrafung für jemanden, der es zu verantworten hat. (Sobald der oder die „weggemobbt“ ist, kommt der geforderte Aus-Schalter.)
  • Microsoft spekuliert, auf die Entwickler Druck ausüben zu können, wenn man WPF-Applikationen sofort als solche erkennt, unter anderem eben am Anti-Aliasing, so in der Art von „Was, Du arbeitest noch mit Windows Forms?“
  • Wie dem auch sei, ein glückliches Ende der Geschichte vom unscharfen Text ist im Moment offenbar nicht in Sicht…

    23. August 2008

    Technologie-Inflation

    Gespeichert unter: Keine Kategorie — Schlagworte: , — René Brunner @ 14:44

    Ein Artikel in der Zeitschrift iX hat mich heute darauf aufmerksam gemacht, dass zusammen mit dem Service Pack 1 für das .NET Framework 3.5 nun nach langem Warten die erste definitive Version des sogenannten ADO.Net Entity Framework zur Verfügung steht.

    Es wurde schon eine ganze Menge darüber geschrieben, was es mit diesen „Entities“ auf sich hat. Z.B. ist die entsprechende Wikipedia-Seite ein guter Startpunkt, um sich einzulesen. Ich will deshalb nicht noch mehr Technisches darüber schreiben, sondern die Gelegenheit ergreifen, um ein bisschen über die Sache zu „philosophieren“.

    Applikationen für vorwiegend administrative Zwecke, wie sie die Megos anbietet, sind sehr stark geprägt durch den Zugriff auf die Daten. Seit wir vor einiger Zeit beschlossen hatten, für die Programm-Entwicklung auf .NET umzusatteln, verfolgte ich deshalb ziemlich aufmerksam, was sich bei .NET in Sachen Datenzugriff und Datenverwaltung tut, und wurde schnell neugierig, als ich vor einiger Zeit zum ersten Mal von diesem Entity Framework hörte.

    Was ich sah, als ich mich näher damit beschäftigte, hat mir zunächst fast die Sprache verschlagen: So ein Riesen-Ding, mit eigener SQL-Variante für die Abfrage, mit eigener Art von Datenbank-Modell, das über das relationale Modell hinausgeht, samt zugehörigem, nicht zu klein geratenem Modellierungs-Tool, plus jeder Menge neuer .NET-Klassen natürlich. Und fast noch bemerkenswerter als die Grösse der ganzen Geschichte kam mir deren Komplexität vor.

    Dann wurde mir klar, dass .NET mit LINQ-to-SQL und dem Entity Framework gleich zwei Technologien enthalten wird, welche sich bezüglich der grundlegenden Aufgabe des sogenannten OR-Mapping überschneiden und konkurrenzieren. Die mögliche Antwort von Microsoft wird vielleicht – nicht unbedingt überraschend – noch mehr Neues, noch mehr Grosses und Komplexes sein, in Form von LINQ-to-Entities.

    Ich habe mich unweigerlich gefragt, wie viele Leute wohl auf der Welt eine Datenbank bewirtschaften müssen mit einer Struktur, die so vielfältig und komplex ist, dass man dieses Entity Framework zum Einsatz bringen kann und netto etwas herausschaut dabei, will sagen: Der Gewinn an Funktionalität und Flexibilität beim Umgang mit der Datenbank in den .NET-Programmen wiegt die Arbeit auf, die man aufwenden muss, um sich in diese riesige Geschichte einzuarbeiten, und wiegt dazu noch den Ärger auf, den man hat durch Bugs, die es fast unweigerlich geben muss in so viel neuem Code.

    Und die Frage „Soll ich auf das Entity Framework setzen?“ hat natürlich noch ganz andere Seiten. Soll ich meine Applikation um eine Technologie herum bauen, die ziemlich Microsoft-spezifisch ist? Wie langlebig wird diese Sache sein? Die Liste der Datenbank-Zugriffs-Technologien, die Microsoft zu „Legacy“ heruntergestuft hat, enthält schon einige Einträge (ODBC, DAO, OLE DB), und vielleicht kommt ja schon in relativ kurzer Zeit ein Eintrag dazu, wenn Microsoft sich eingestehen müsste, dass zwei OR Mappers einer zuviel ist.

    Interessanterweise ist es mir bei einer Google-Suche als Vorbereitung auf das Schreiben dieses Blog-Eintrags nicht gelungen, Leute zu finden, die sich wie ich angesichts der Grösse, der Komplexität und des proprietären Anstrichs des Entity Framework Sorgen machen und erst einmal abwarten, bevor sie es einsetzen. Aber vielleicht ist es dafür einfach noch etwas zu früh…

    16. August 2008

    ReadOnlyCollection

    Gespeichert unter: Keine Kategorie — Schlagworte: , — René Brunner @ 13:59

    Jeder, der eine halbwegs umfangreiche Klassen-Sammlung in C# designen muss, hat gute Chancen, auf folgende grundlegende Design-Frage zu stossen: Eine Klasse soll eine List enthalten, die zwar gegen aussen sichtbar ist, die man aber nicht direkt verändern darf – sämtliche Änderungen sollen quasi indirekt mit Hilfe von Methoden der Klasse erfolgen. Für eine solche Anforderung kann es viele denkbare Gründe geben; schon nur, wenn man die Anzahl Änderungen an der List zählen möchte, sollte es besser nicht möglich sein, dass sich jemand an der Zählung vorbeimogelt, indem er sich die Liste geben lässt und sie dann selbst verändert.

    Ein kleines synthetisches Codebeispiel hierzu:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public List<int> Numbers {
          get { return numbers; }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c=new Container();
          c.AddNumber(5);     // soll nur so funktionieren
          c.Numbers.Add(5);   // soll verboten sein
        }
      }
    }
    

    Mein erster Gedanke war, dass es in C# vielleicht ein Äquivalent zu C++ const gibt und man damit etwas machen kann. Eine Abklärung ergab, dass die CLR zwar eine gewisse Unterstützung bietet in dieser Richtung (für Managed C++), diese aber in C# nicht zur Verfügung steht.

    Dann stiess ich auf die Property IsReadOnly, welche im Interface IList enthalten ist. Das sieht zwar auf den ersten Blick hoffnungsvoll aus, aber die Anwesenheit dieser Property im Interface heisst noch lange nicht, dass man im Falle einer „templated class“ etwas damit machen kann. Ich habe auf jeden Fall keinen Weg gefunden, im konkreten Falle einer List<int> deren Property IsReadOnly irgendwie zu überdefinieren, und selbst wenn dies gelänge, würden sich wohl Methoden wie Add der Template-basierten Klasse überhaupt nicht dafür interessieren.

    Schliesslich förderte meine Suche die Klasse ReadOnlyCollection zu Tage, welche man wie folgt auf das Problem ansetzen kann:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public ReadOnlyCollection<int> Numbers {
          get { return numbers.AsReadOnly(); }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c = new Container();
          c.AddNumber(5);     // funktioniert nur so
          c.Numbers.Add(5);   // compiliert nicht, 'ReadOnlyCollection.Add' gibt es nicht
        }
      }
    }
    

    Etwas unbefriedigend an dieser Lösung ist, dass mit Hilfe der Methode AsReadOnly ein neues Objekt erzeugt werden muss.

    In irgendeinem Forum habe ich dann folgende Lösungs-Variante gefunden, welche ohne ein neues Objekt auskommt:

    namespace ReadOnly {
      class Container {
    
        private List<int> numbers;
        public IEnumerable<int> Numbers {
          get { return numbers; }
        }
    
        public void AddNumber(int n) {
          numbers.Add(n);
        }
    
        public Container() {
          numbers = new List<int>();
        }
      }
    
      class Program {
        static void Main(string[] args) {
          Container c = new Container();
          c.AddNumber(5);     // funktioniert nur so
          c.Numbers.Add(5);   // compiliert nicht, 'IEnumerable.Add' gibt es nicht
        }
      }
    }
    

    Eine List<int> implementiert natürlich selbst bereits das Interface IEnumerable, so dass die Sache rein zur Compilierzeit stattfindet und die Property Number technisch gesehen gleich die Liste selbst zurückgibt. Unschön ist allerdings, dass man mit einem IEnumerable-Objekt nichts weiter machen kann als per foreach die Elemente durchgehen; noch nicht einmal die Anzahl Elemente kann man direkt abfragen.

    Nach einigem Abwägen habe ich beschlossen, für die Megos-eigene Klassen-Bibliothek Triton, die gerade entsteht, das Problem zu ignorieren und keine technische Vorkehrungen zu treffen, um mit Hilfe einer der geschilderten Methoden Veränderungen an solchen Listen zu verhindern. Wir sind wenige, erfahrene, disziplinierte Programmierer, die keine Mühe haben mit dem Befolgen von Konventionen wie „Verändere keine Listen-Properties direkt“.

    Natürlich sähe das anders aus, wenn man z.B. eine kommerziell vertriebene Klassen-Bibliothek für den Gebrauch durch viele andere Programmierer bauen müsste. Aber auch da gäbe es vielleicht die Möglichkeit, die direkten Veränderungen selbst nicht zu verunmöglichen, sie aber dennoch zu entdecken und mit einer Exception zu beantworten, indem man einerseits die Anzahl Aufrufe von AddNumber zählt und andererseits an „strategischen“ Orten im Code die Anzahl Elemente der Liste gegen diesen Zähler prüft.

    14. Juni 2008

    Mehrfachvererbung

    Gespeichert unter: Keine Kategorie — Schlagworte: — René Brunner @ 15:33

    Vor einigen Wochen stand ich recht unerwartet vor einem trickreichen Design-Problem, bei dem es sich lohnen düfte, hier davon zu erzählen.

    Für unsere im Entstehen begriffene neue .NET-basierte Programmierumgebung Triton wollte ich eine neue Control-Klasse definieren. Es ging darum, die Fokus-Steuerung, die Validierung und das Melden von Fehlern gegenüber der Standard-Klasse Form zu verbessern und zu generalisieren, und das bedeutete auch gewisse Erweiterungen bei der Funktionalität der Controls.

    Also, an die Arbeit, und eine Basis-Klasse TritonControl definieren, welche die nötigen grundsätzlichen Erweiterungen und die Zusammenarbeit mit TritonForm enthält, und dann TritonTextBox, TritonCheckBox usw. davon ableiten…

    Aber Moment mal: Wie soll das überhaupt gehen? Man kann der bestehenden Klasse System.Windows.Forms.TextBox ja keine neue Basis-Klasse TritonControl „unterjubeln“ bzw. sich in die Klassenhierarchie irgendwo zwischen Control und TextBox hineinzwängen. Auf der anderen Seite, gegen „oben“ in der Hierarchie, ist es zwar einfach, von TextBox eine TritonTextBox abzuleiten, aber so ergibt sich natürlich auch keine gemeinsame Basis-Klasse, sondern beim Ableiten von einem Dutzend .NET-Control-Klassen nur ein Dutzend typenmässig inkompatibler neuer Klassen, mit denen sich kein vernünftiges System bauen lässt.

    Es gibt meiner Meinung nach nicht viel, was C++ der Sprache C# voraus hat, aber immerhin: In C++ wäre man jetzt hingegangen und hätte locker per Mehrfachvererbung die neue Klasse TritonTextBox eben von TextBox und TritonControl abgeleitet. Das ist so in C# nicht möglich.

    Eine Analyse des Problems zeigte zwei mögliche Lösungen:

    Erstens könnte man TritonControl von UserControl ableiten, und TritonTextBox wiederum von TritonControl. Ein solches Control würde dadurch zu einer Eingabemöglichkeit für einen Text, indem es zur Laufzeit dynamisch ein Child Control für sich vom richtigen Typ erzeugt, konkret eine System.Windows.Forms.TextBox, oder indem man im Designer statisch dem UserControl ein solches Child Control gibt.

    Zweitens könnte man TritonTextBox von TextBox ableiten, aber zusätzlich mit einem Interface ITritonControl ausstatten.

    Beim ersten Ansatz ist hauptsächlich unschön, dass man eine Menge Properties definieren muss in den von TritonControl abgeleiteten Klassen, damit deren Werte an die „inneren“, quasi an die echten Controls, weitergegeben werden können.

    Beim zweiten Ansatz ist unschön, dass man das Interface mit einer ganzen Reihe von Methoden und Properties bei jedem abgeleiteten Control separat implementieren muss.

    Nach einigen Überlegungen entschieden wir uns für den zweiten Ansatz. Das Implementieren des Interface ist zwar eine gewisse Fleissarbeit, aber dafür hat man sicher keinen Ärger mit dem Designer, für den eine TritonTextBox immer noch eine waschechte TextBox ist, mit der richtigen visuellen Darstellung, dem richtigen Design-Verhalten, und allen interaktiv spezifizierbaren Eigenschaften, für welche man die .NET-Controls so mag.

    19. April 2008

    Die Ursprünge von C#

    Gespeichert unter: Keine Kategorie — Schlagworte: , — René Brunner @ 14:36

    Wenn Sie mal eine Pause einlegen wollen von all der anstrengenden C#-Programmierarbeit, kann es vielleicht interessant sein, sich anzuschauen, wo denn C# eigentlich herkommt.

    Wenn man ein fertiges Sprach-Design vor sich hat, und noch viel mehr, wenn man eine Weile mit der jeweiligen Programmiersprache gearbeitet hat, fällt es sehr schwer sich vorzustellen, dass jemand dieses Design irgendwann in der Vergangenheit erarbeiten musste, und dass dies in den meisten Fällen ein hartes Stück Arbeit war: Einmal geschaffen, haben es solche Designs so an sich, irgenwie selbstverständlich oder sogar trivial auszusehen, aber sie sind alles andere als das!

    Im Falle von C# ist ein gewisser Anders Hejlsberg der Mann, der als Architekt für einen grossen Teil des Sprach-Designs verantwortlich ist. Microsoft machte 1996 einen guten Fang, als es der Firma gelang, diesen Mann bei Borland abzuwerben, und ihn zum Chef-Designer im Team machte, das die C#-Sprache entwickelte.

    Zu erstem Ruhm gelangte Hejlsberg bereits 1983, als sein Pascal-Compiler Turbo Pascal auf den Markt kam. Dieser Compiler deklassierte mit seiner Geschwindigkeit alles bisher Dagewesene komplett.

    Wenn Sie neugierig geworden sind, ein paar interessante weiterführende Links:
    Ein Interview mit Anders Hejlsberg über das Design von C#
    Wikipedia über Anders Hejlsberg
    Wikipedia über Turbo Pascal

    Und zu guter letzt noch etwas für Nostalgiker, z.B. für Leute wie mich, die damals 1983 die Ankunft von Turbo Pascal selbst miterlebt haben und kaum glauben konnten, was sie da sahen: Borland hat den Compiler in die Public Domain gegeben; man kann Version 1.0 hier herunterladen, und das Ding läuft sogar in der DOS-Box von Windows XP!

    Bloggen Sie auf WordPress.com.