Ein eigener Datentyp (Teil 6)

Im letzten Teil (siehe: Ein eigener Datentyp (Teil 5)) haben wir uns um die Konvertierung aus Standard-Datentypen gekümmert. In diesem Teil soll es nun um die überschriebenen Methoden der Basisklasse – Object – gehen. Hier müssen wir die Implementierung für drei Methoden vornehmen, „Equals(object)“, „GetHashCode()“ sowie „ToString()“. Beginnen wir mit der „Equals“-Methode. Diese ist eigentlich auch schon die „komplizierteste“ der drei genannten. Hier würde ich die folgende Implementierung vorschlagen:

public override bool Equals(object obj)
{
    return ((obj is Int24) && (Value == ((Int24)obj).Value)) || ((obj is int) && (Value == (int)obj));
}

Weiterlesen

Ein eigener Datentyp (Teil 5)

Im letzten Teil (siehe: Ein eigener Datentyp (Teil 4)) haben wir die „Parsing“-Methoden implementiert. In diesem Teil wird es um die Methoden zur Konvertierung aus Standardtypen gehen. Unter Standardtypen verstehen sich folgende: byte, sbyte,  short, ushort, int, uint, long, ulong, float, double, decimal sowie string (welchen wir theoretisch bereits im letzten Teil implementiert haben). Beginnen wir also mit den beiden Byte-Typen.

public static Int24 ConvertFromByte(byte value)
{
    return new Int24(value);
}

public static Int24 ConvertFromSByte(sbyte value)
{
    return new Int24(value);
}

Nicht weiter kompliziert. Da ein Byte niemals außerhalb der Reichweite unseres Typen sein kann, benötigen wir keine weiteren Aktionen. Dies wird bei späteren Typen anders aussehen und auch beim UInt24 würde dies unter Umständen wegen den vorzeichenbehafteten Typen anders aussehen. Weiterlesen

Ein eigener Datentyp (Teil 4)

Im letzten Teil (siehe: Ein eigener Datentyp (Teil 3)) haben wir die letzten Operatoren implementiert. In diesem Part geht es um die „Parsing“-Methoden. Diese Methoden sollen dazu dienen das Parsing von Strings zu ermöglichen. Hierfür gibt es an den Standarddatentypen die Statischen-Methoden „TryParse“ sowie „Parse“. Auch wir wollen nun diese Methoden implementieren und zur Verfügung stellen. Hierbei ist „TryParse“ quasi Exception sicher (hier werden die Exceptions gecatcht und anschließend ein false zurück gegeben). Beginnen wir mit den beiden Varianten der „TryParse“-Methode. Diese könnten wie folgt aussehen:

public static bool TryParse(string s, out Int24 result)
{
    return TryParse(s, NumberStyles.Integer, null, out result);
}

public static bool TryParse(string s, NumberStyles style, IFormatProvider formatProvider, out Int24 result)
{
    int output;
    bool canParse = Int32.TryParse(s, style, formatProvider, out output);

    if (!canParse || output > IntMaxValue || output < IntMinValue)
    {
        result = new Int24();
        return false;
    }

    result = new Int24(output);
    return true;
}

Während die kurze Fassung dieser Methode lediglich unsere längere aufruft, nutzt die ausführlich implementierte Fassung nur die „TryParse“-Methode des 32-Bit Integers. Zusätzlich werden hier allerdings noch unsere begrenzten Max- und Minwerte geprüft.   Weiterlesen

Ein eigener Datentyp (Teil 3)

Im letzten Teil (siehe: Ein eigener Datentyp (Teil 2)) haben wir uns um die Implementierung der Grund-Operatoren gekümmert. In diesem Teil wollen wir uns den Vergleichs- sowie Bitoperatoren wenden, welche ebenfalls eine entschiedene Bedeutung für Datentypen haben. Hierfür müssen wir uns jedoch zunächst darüber im Klaren sein, dass wir letztendlich nur eine Einschränkung eines Int32-Datentypes erstellen und deshalb erneut, wie auch bei den Teilen zuvor, von den bereits in Int32 implementierten Methoden Gebrauch machen können. Die hier wohl wichtigsten Operatoren sind jene, die uns die Gleicheit bzw. Ungleichheit bestätigen. Diese würden, da wir eh nur eine Integer-Spezifikation verwenden, wie folgt aussehen:

public static bool operator ==(Int24 value1, Int24 value2)
{
    return value1.Value == value2.Value;
}

public static bool operator !=(Int24 value1, Int24 value2)
{
    return value1.Value != value2.Value;
}

Auch hier ist wieder zu erkennen, dass man es sich als Entwickler oft sehr einfach machen kann. Wobei an dieser Stelle ebenfalls bedacht werden sollte, dass bei einem wirklich eigenen Typen der nicht eine so große Ähnlichkeit mit einem anderen bereits existierenden Typen hat, natürlich viel mehr Aufwand benötigt wird.  Weiterlesen

Ein eigener Datentyp (Teil 2)

Im letzten Teil (siehe: Ein eigener Datentyp (Teil1)) haben wir uns mit dem Grundgerüst unseres Datentypen zufrieden gegeben. Diesmal sollen die Operatoren implementiert werden. Der wohl wichtigste Operator hierfür dürfte der „implicit“-Operator oder auch Zuweisungsoperator sein. Auch hier werden wir wieder zwischen einem normalen Integer-Wert und einem Byte-Array unterscheiden und zwei Implementierungen vornehmen. Trotz der enormen Wichtigkeit dieses Operators ist dieser dennoch sehr simpel zu implementieren.

public static implicit operator Int24(int value)
{
    return new Int24(value);
}

public static implicit operator Int24(byte[] value)
{
    return new Int24(value);
}

Wie im Sourcecode zu sehen wird nur eine neue Instanz eines 24-Bit Integers erzeugt und zurück gegeben. Da wir bereits die nötigen Konstruktoren implementiert haben, haben wir keinen Aufwand mehr mit dieser Methode.  Weiterlesen

Ein eigener Datentyp (Teil 1)

Ein eigener Datentyp kann dann sinnvoll sein, wenn es Voraussetzung ist, Daten in ein Gerät zu schreiben bei denen der Speicherplatz begrenzt ist oder wenn es notwendig ist einen Typen mit einer ganz speziellen Interaktion zu besitzen. Aber wie kann man einen eigenen Datentyp mit sämtlichen Funktionalitäten wie z.B. die eines Integers erzeugen? Nun eigentlich ist das gar nicht so schwer wie man vielleicht denkt, denn .NET bietet dafür bereits einige Schnittstellen an und der andere Teil sind überwiegend die korrekten Operator-Überladungen. In Rahmen dieser Mini-Serie möchte ich einen eigenen 24-Bit großen Integer erstellen, wie man ihn z.B. bei einigen Feldgeräten benötigt. Am Ende des letzten Teils werde ich anschließend den Quellcode sowohl für die Signed, als auch für die Unsigned Variante dieses Typen anhängen. Aber beginnen wir nun mit den Int24-Typen.

Zunächst einmal muss klar sein, was der Unterschied zwischen einer Struktur und einer Klasse ist,  dies wird hier allerdings vorausgesetzt. Und das ist auch eigentlich schon alles was notwendig ist, um den Typen zu erstellen. Wir werden ebenfalls die selben Attribute sowie Interfaces wie ein Int32 verwenden, um die Kompatibilität zu maximieren.  Weiterlesen