Objekte ordnungsgemäß mit Dispose und Destruktor (Finalize) zerstören

Im Beispiel wird gezeigt, wie ein Objekt prinzipiell ordnungsgemäß zerstört werden kann. Dispose() wird dabei vom Code aus aufgerufen, der Destruktor zu einem unbestimmten späteren Zeitpunkt vom GarbageCollector.

  • weiterführende Informationen zu Destuktoren, Finalize, Dispose: Link
public class MyClass : IDisposable
{
    private bool _bDisposed = false;

    // Konstruktor
    public MyClass()
    {
    }

    // Destruktor, Ersatzmakro für
    // protected override void Finalize()
    ~MyClass()
    {
        this.Dispose(false);
    }

    // öffentliche Dispose-Methode zum Aufräumen
    public void Dispose()
    {
        this.Dispose(true);
    }

    // interne Dispose-Methode
    private void Dispose(bool bDisposing)
    {
        if (!_bDisposed)
        {
            if (bDisposing)
            {
                // hier managed Resourcen freigeben
            }
        }

        _bDisposed = true;
    }
}

Datentypen in C#

Typ      Byte  Bit  Laufzeittyp  Beschreibung                              Wertebereich                                               Genauigkeit

byte     1     8    Byte         Byte-Wert ohne Vorzeichen                 0 bis 255
sbyte    1     8    SByte        Byte-Wert mit Vorzeichen                  -128 bis 127
short    2     16   Int16        Short-Wert mit Vorzeichen                 -32.768 bis 32.767
ushort   2     16   UInt16       Short-Wert ohne Vorzeichen                0 bis 65.535
int      4     32   Int32        Integer-Wert mit Vorzeichen               -2.147.483.648 bis 2.147.483.647
uint     4     32   UInt32       Integer-Wert ohne Vorzeichen              0 bis 4.294.967.295
long     8     64   Int64        langer integer-Wert mit Vorzeichen        -9.223.372.036.854.775.808 bis 9.223.372.036.854.775.807
ulong    8     64   UInt64       langer integer-Wert ohne Vorzeichen       0 bis 18.446.744.073.709.551.615
float    4     32   Single       Gleitkommazahl                            ± 1.5e-45 bis ± 3.4e38                                     7

double   8     64   Double       Gleitkommazahl mit doppelter Genauigkeit  ± 5.0e-324 bis ± 1.7e308                                   15-16
decimal  16    128  Decimal      Zahl mit fester Genauigkeit               ± 1,0e-28 bis ± 7,9e28                                     28-29

string              String       Unicode-Zeichenfolge   
char     2     16   Char         Unicode-Zeichen                           U+0000 bis U+ffff
   
bool     1     8    Boolean      Boolescher Wert                           true, false

Interfaces deklarieren

  • Interfaces (Schnittstellen) beschreiben Verhaltensweisen von unabhängigen Objekten (Klassen)
  • implementieren abstrakte, schreibgeschützte Methoden, Eigenschaften und Indexer
using System;
using System.Text;
using System.Management;
using System.Collections.Generic;

// einen Motor definieren
public interface IMotor
{
    int Drehzahl
    {
        get;
    }
}

// einen Display definieren
public interface IDisplay
{
    int Helligkeit
    {
        get;
    }
}

// einen Schalter definieren
public interface ISchalter
{
    bool Status
    {
        get;
    }
}

// Maschine besteht mindestens aus einem Motor und einem Schalter
public interface IMaschine : IMotor, ISchalter
{
    void An();
    void Aus();

    int Gewicht
    {
        get;
    }

    string Name
    {
        get;
    }
}

// Maschine ohne Display, nur mit Motor und Schalter
public class KleineMaschine : IMaschine
{
    private int iMotorDrehzahl = 0;  // Motordrehzahl
    private int iGewicht = 100;  // Gewicht
    private bool bStatus = false;  // Schalterstatus
    private string sName = "-";  // Name der Maschine

    // Konstruktor
    public KleineMaschine(string sBezeichner)
    {
        sName = sBezeichner;
    }

    // Implementation der im Interface IMotor deklarierten Drehzahl
    public int Drehzahl
    {
        get
        {
            return iMotorDrehzahl;
        }

        set
        {
            iMotorDrehzahl = value;
        }
    }

    // Implementation der im Interface ISchalter deklarierten Schalterstellung
    public bool Status
    {
        get
        {
            return bStatus;
        }

        set
        {
            bStatus = value;
        }
    }

    // Implementation des im Interface IMaschine deklarierten Gewichts
    public int Gewicht
    {
        get
        {
            return iGewicht;
        }

        set
        {
            iGewicht = value;
        }
    }

    // Implementation des im Interface IMaschine deklarierten Namens
    public string Name
    {
        get
        {
            return sName;
        }

        set
        {
            sName = value;
        }
    }

    // Implementation der im Interface IMaschine deklarierten Funktion
    public void An()
    {
        Console.WriteLine("{0} ist an, Drehzahl = {1}.", sName, iMotorDrehzahl);
    }

    // Implementation der im Interface IMaschine deklarierten Funktion
    public void Aus()
    {
        Console.WriteLine("{0} ist aus.", sName);
    }
}

// neuen Maschinentyp, abgeleitet von KleineMaschine mit einem zus. Display
public class GrosseMaschine : KleineMaschine, IDisplay
{
    private int iDisplayHelligkeit = 0;

    // Konstruktor der Klasse, ruft den Konstruktor von der Basisklasse "KleineMaschine" auf
    public GrosseMaschine(string sBezeichner)
        : base(sBezeichner)
    {
    }

    // Implementation der im Interface IDisplay deklarierten Displayhelligkeit
    public int Helligkeit
    {
        get
        {
            return iDisplayHelligkeit;
        }

        set
        {
            iDisplayHelligkeit = value;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Liste mit Maschinen
        List<IMaschine> MaschinenListe = new List<IMaschine>();

        // kleine Maschine erzeugen (Motor + Schalter)
        KleineMaschine KM = new KleineMaschine("kleine Maschine");
        KM.Gewicht = 100;
        KM.Drehzahl = 100;
        KM.Status = true;

        MaschinenListe.Add(KM);

        // große Maschine erzeugen (Motor, Schalter, Display)
        GrosseMaschine GM = new GrosseMaschine("große Maschine");
        GM.Gewicht = 200;
        GM.Drehzahl = 1000;
        GM.Helligkeit = 80;
        GM.Status = true;

        MaschinenListe.Add(GM);

        // Liste durchgehen, Objekte wieder herausholen und Möglichkeiten austesten
        foreach (IMaschine ma in MaschinenListe)
        {
            Console.WriteLine(ma.Name + " ist vom Typ " + ma.GetType().ToString());
            Console.WriteLine("Gewicht: {0}kg", ma.Gewicht);

            ma.An();

            // Beispiel: Typ der Maschine ermitteln
            if (ma.GetType() == typeof(KleineMaschine))
            {
                
            }

            // Beispiel: Objekt mit "as" interpretieren
            GrosseMaschine gmObj = ma as GrosseMaschine;

            // wenn sich das Obj. als große Maschine interpretieren lässt,
            // dann besitzt es auch eine Eigenschaft Displayhelligkeit
            if (gmObj != null)
            {
                Console.WriteLine("Die Maschine hat ein Display mit der Helligkeit: {0}", gmObj.Helligkeit);
            }

            // prüfen, ob das Objekt verschiedene Interfaces implementiert
            IMotor iM = ma as IMotor;

            if (iM != null)
            {
                Console.WriteLine("Die Maschine implementiert das Interface IMotor");
            }

            IDisplay iD = ma as IDisplay;

            if (iD != null)
            {
                Console.WriteLine("Die Maschine implementiert das Interface IDisplay");
            }

            ISchalter iS = ma as ISchalter;

            if (iS != null)
            {
                Console.WriteLine("Die Maschine implementiert das Interface ISchalter");
            }
            
            ma.Aus();
        }

        Console.ReadLine();
    }
}

String zu Typ wandeln (Parse, TryParse)

Einfache Beispiele

// Beispiele für Parse
int i = int.Parse("-100");
uint ui = uint.Parse("100");
long l = long.Parse("100");
float f = float.Parse("100,1");
double d = double.Parse("-100,1");
bool b = bool.Parse("True");

// Beispiele für TryParse
bool bValue = true;
if (bool.TryParse("False", out bValue ))
{
    ...
}

double dValue;
if (double.TryParse("0,45", out dValue))
{
    ...
}

Komplexere Beispiele

Häufig kommt es vor, dass z.B. CSV-Dateien eingelesen werden müssen und der vorhandene Datenbestand Werte mit unterschiedlichsten Dezimaltrennzeichen aufweist. Daher ist es wichtig entsprechend dem Dezimaltrennzeichen eine passende Konvertierungsfunktion zu schreiben.

// kulturabhängig Fließkommazahlen einlesen:
// Fließkommazahlen entsprechend der Culture des Hostsystems einlesen:
if (double.TryParse("0,45", NumberStyles.Float, new CultureInfo(CultureInfo.CurrentCulture.Name, false), out dValue))
{
    ...
}

// kulturunabhängig Fließkommazahlen einlesen:
// wenn Fließkommazahlen, die mit "." anstelle von "," getrennt sind, auf einem deutschsprachigen Hostsystem eingelesen werden sollen:
if (double.TryParse("0.45", NumberStyles.Float, CultureInfo.InvariantCulture, out dValue))
{
    ...
}

Enumerator anlegen und benutzen

// allg. Definition
public enum MyType
{
    FileType,
    DirectoryType
}

// Definition mit vorgegebenen Werten
public enum MyErrorType
{
    FileError = 20,
    DirectoryError = 30
}

// Deklaration
private MyType _MyOwnType = MyType.DirectoryType;
private MyErrorType _MyError = MyErrorType.FileError;

// Vergleich mit int-Wert
int iErrorValue = 20;

// int-Wert in enum wandeln
MyErrorType err = (MyErrorType)Enum.ToObject(typeof(MyErrorType), iErrorValue);

// Auswertung
switch (err)
{
    case MyErrorType.FileError:
        break;
    case MyErrorType.DirectoryError:
        break;
}