.NET Guidelines for Libraries
Wichtig zu verstehen ist dabei, dass sich diese Richtlinien nur auf die öffentliche Schnittstelle (also insbesondere Member mit
public
- oder protected
-Modifizierer) beziehen und grundsätzlich keine Aussagen zu internen (private
-Modifizierer) Membern treffen. Es bietet sich jedoch durchaus an, auch hier konform zu gehen. Die Einleitung weist auch explizit darauf hin, dass ein – gut begründetes – Abweichen von diesem Regelwerk legitim ist.Im MSDN findet sich im Übrigen auch eine Übersicht der Warnungen bei der Analyse von verwaltetem Code.
UNIX Timestamps and C#
DateTimeOffset
-Struktur bereithält:
FromUnixTimeSeconds(…)
(undFromUnixTimeMilliseconds(…)
)ToUnixTimeSeconds(…)
(undToUnixTimeMilliseconds(…)
)
Die Verwendung gestaltet sich wie üblich sehr einfach:
010203040506070809
// UNIX-Zeitstempel für aktuelles Datum und aktuelle Uhrzeit ermittelnlong unixTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// bestimmtes Datum um 0:00 Uhr verwendenunixTimestamp = (new DateTimeOffset(new DateTime(1988, 1, 29))).ToUnixTimeSeconds();
// DateTime-Objekt lokaler Zeit aus UNIX-Zeitstempel erzeugenDateTime dateTime = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp).LocalDateTime;
Get Enum Value by String
Ein klassischer Fall im Bereich der Webentwicklung ist die Zusammenarbeit aus Anwendung und Datenbank, beispielsweise hier im Blog zwischen der Programmiersprache C# mit ASP.NET MVC-Framework und MySQL-Datenbank. Etwas konkreter soll es darum gehen, C#-Aufzählungstypen zusammen mit MySQL-ENUMs zu verwenden, welche grundsätzlich erst einmal als bloße Zeichenketten zu behandeln sind. Für das folgende Beispiel nehmen wir an, dass eine Tabelle
user
existiert, die eine Spalte state
vom Typ ENUM('ACTIVE','INACTIVE','LOCKED')
enthält.Unter Verwendung des ADO.NET Entity Framework würde beim Database First-Ansatz eine entsprechende Klasse
user
mit der Eigenschaft state
vom Typ string
erzeugt. Da es sich um eine partielle Klasse handelt, erweitern wir diese um eine neue Eigenschaft State
. Diese soll anschließend die automatische Konvertierung für state
übernehmen und ermöglicht uns im Programmcode einen typsicheren Zugriff auf den Status des Benutzers:
user
010203040506070809
public partial class user { public UserState State { get { return (UserState) Enum.Parse(typeof(UserState), this.state, true); } set { this.state = value.ToString().ToUpper(); } }
0102030405060708091011121314151617
user dbUser = new user() { State = UserState.Active}; // üblicherweise aus Datenbank ermittelt
string state = dbUser.state; // "ACTIVE"UserState userState = dbUser.State; // Active
dbUser.State = UserState.Inactive;
state = dbUser.state; // "INACTIVE"userState = dbUser.State; // Inactive
dbUser.state = "LOCKED";
state = dbUser.state; // "LOCKED"userState = dbUser.State; // Locked
Enum.Parse
-Methoden finden sich wie üblich im MSDN. Es lohnt sich außerdem ein Blick auf die Enum.TryParse(…)
-Methoden mit generischem Typ-Parameter. DNS Resolving with C#
Unser Hauptanliegen soll es nun sein, dieses System per C# zu befragen, um darauf aufbauend in einem späteren Beitrag eine konkrete Anwendung umzusetzen. Praktischerweise liefert das .NET-Framework mit
System.Net.Dns
eine Klasse mit entsprechender Funktionalität – zugegebenermaßen aber nur mit geringem Funktionsumfang, weshalb zur professionellen Arbeit mit den verschiedenen Resource Records das Einbinden externer Programmbibliotheken sinnvoll sein kann. Die Anwendung der Basisfunktionalität ist jedoch denkbar einfach:
0102030405060708
IPAddress[] hostAddressList = Dns.GetHostAddresses("coders-online.net");
foreach(IPAddress hostAddress in hostAddressList) { /** * hostAddress enthält nun jeweils eine IP-Adresse zur Domain; * im Falle dieses Beispiels den einzigen Eintrag 217.160.176.125. **/}
Dns.GetHostName()
, welche den Namen des lokalen Rechners liefert. Das MSDN liefert wie üblich weitere Informationen zur Dns
-Klasse, u. a. mit Hinweisen zu den asynchronen Methoden. Weiterhin interessant im System.Net
-Namespace ist bis dahin natürlich auch die Klasse IPAddress
. Typing
Nun gibt es verschiedene Möglichkeiten, ein solches System konkret zu implementieren. Dieser Beitrag soll explizit nicht dazu dienen, das eine System zu verteufeln und das jeweils andere hochzuloben. Dennoch haben die meisten Entwickler – so auch ich – eine gewisse Präferenz, sofern die Situation kein besonderes Vorgehen erfordert und man in der Wahl somit weitestgehend frei ist. Natürlich haben jeweils "beide Welten" ihre Vor- und Nachteile.
Dazu möchte ich einige Gegenüberstellungen mit Beispielen präsentieren, deren Definitionen jedoch nicht unbedingt als allgemeingültige Aussage zu verstehen sind, sondern vielmehr vom Kontext abhängig sein können:
Dynamisch vs. Statisch
Bei der statischen Typprüfung sind die Typen bereits zum Zeitpunkt der Entwicklung bekannt und werden entweder explizit vom Entwickler angegeben, oder aber implizit vom System abgeleitet (mehr dazu im nächsten Abschnitt). Bei der dynamischen Typprüfung findet die Prüfung der Typen erst zur Laufzeit statt.
- Dynamisch: z. B. C++ (optional), C# (optional), JavaScript, Lua, PHP, Prolog, Python, Ruby, Scheme
- Statisch: z. B. Ada, C++ (standardmäßig), C# (standardmäßig), Haskell, Java
Ich bevorzuge hier, sofern die Umstände nicht dagegen sprechen, die statische Typisierung. Für mich überwiegt hier der Vorteil der Typprüfung zur Entwicklungs- bzw. Kompilierzeit. Viele Fehler, die oftmals erst während der Laufzeit auffallen, können so effektiv vermieden werden. Durch Konzepte wie die generische Programmierung kann hier der notwendige Mehraufwand zwar deutlich reduziert werden, dennoch erfordert eine statische Typisierung in der Regel (minimal) mehr Aufwand bei der Entwicklung und kann mitunter umständliche Konstrukte bei sehr dynamischer Datenverarbeitung – beispielsweise im Web-Bereich – erforderlich machen; s. Dynamische Typisierung in C#.
Explizit vs. Implizit
Bei der expliziten Angabe der Typen trägt man als Entwickler Verantwortung dafür, den zum angedachten Inhalt einer Variablen (oder Rückgabe einer Methode) passenden Typen auszuwählen. Bei impliziter Ableitung erledigt dies das Typsystem, indem es den passenden Datentyp zum Inhalt annimmt.
- Explizit: z. B. Ada, C++, C# (standardmäßig), Java
- Implizit: z. B. C# (optional), Haskell, JavaScript, Lua, Prolog, Python, Ruby, PHP, Scheme
Ich bevorzuge hier, sofern die Umstände nicht dagegen sprechen, die explizite Typangabe. Diese bedeutet üblicherweise zwar etwas mehr Schreibaufwand, erhöht aus meiner Sicht jedoch die Verständlichkeit des Quelltextes, da ich die Bezeichner von Variablen ungerne mit Präfixen oder Suffixen versehe, sondern mich bei der Benennung auf den Inhalt bzw. Zweck konzentrieren möchte. Um eine Kleinigkeit zu testen oder für ansonsten sehr umständliche Konstrukte (vgl. generische Programmierung) empfinde ich implizite Typableitung jedoch durchaus komfortabel. Teilweise kann dies sogar notwendig sein; s. Implizite Typisierung in C#.
Stark vs. Schwach
Dieser Aspekt behandelt im erweiterten Sinne die Typsicherheit des Typsystems. Stark typisierte Programmiersprachen erlauben für gewöhnlich – wenn überhaupt – nur implizite Typumwandlungen, sofern kein Datenverlust auftritt (beispielsweise von einem ganzzahligen Datentyp kleineren Wertebereiches zu einem mit größerem Wertebereich). Schwächer typisierte Programmiersprachen sind hier für gewöhnlich "großzügiger".
- Stark: z. B. Ada, C++, C#, Haskell, Java, Python, Scheme
- Schwach: z. B. JavaScript, Lua, Prolog, Ruby, PHP
Beispiel in PHP
0102030405
$tmp = 27;
if($tmp) { // implizite Auswertung als "true" echo 'klappt!';} // Ausgabe von "klappt!", da Zahlen ungleich "0" als "true" ausgewertet werden
Ich bevorzuge hier, sofern die Umstände nicht dagegen sprechen, die starke Typisierung. Der Grund ist schlicht der, dass so weitestgehend sichergestellt ist, dass keine unerwarteten oder gar fehlerhaften Konvertierungen vom System vorgenommen werden – sofern ich dem nicht explizit zustimme, wozu die meisten Programmiersprachen entsprechende Typumwandlungen vorsehen. Auch hier ist jedoch zugegebenermaßen üblicherweise ein etwas höherer Aufwand notwendig, als bei eher schwächer typisierten Programmiersprachen.
Meine persönliche Präferenz statischer, expliziter und starker Typsysteme ist tatsächlich auch als eben solche zu verstehen. Ich erkenne durchaus den Vorteil eher "dynamischerer" Sprachen an und nutze diesen ebenfalls in einigen Projekten. Ich habe jedoch für mich festgestellt, mit o. g. Verhalten produktiver zu arbeiten und halte mich daher soweit sinnvoll an solche Sprachen. Insbesondere in C# – was wohl kaum eine Überraschung sein dürfte – finde ich hier eine sehr gute Kombination dieser Aspekte umgesetzt. Wem bisher nur die eine Seite geläufig ist, empfehle ich auf jeden Fall, sich auch einmal eine Sprache mit anderem Typsystem genauer anzusehen.Insgesamt ist dies eine sehr grobe Einteilung, von der viele Programmiersprachen eine etwas differenziertere vornehmen und tlw. auch Kombinationen erlauben. Dennoch eignet sich dies durchaus für einen ersten Überblick der Möglichkeiten; einige Aspekte hängen auch bis zu einem gewissen Grad voneinander ab. Interessierte sollten sich definitiv beispielsweise einmal vom entsprechenden Wikipedia-Artikel ausgehend weiter informieren.
Project links
-
BitStadt – Stadtportal
Berlin · Hamburg · Amsterdam -
CCC – Fahrplan
Schedules for the CCCongress
Categories / Archive | Übersicht
- PHP functions in C# (136)
- Dictionary (257)