Archive

Posts Tagged ‘c#’

Enums

May 29th, 2007 No comments

Enums sind ein einfacher und komfortabler Weg um z. B. Status- oder Modus-Indikatoren zu speichern.
Jeder Entwickler braucht dieses Feature wohl tagtäglich, sei es über “built-in” Enumerationen wie System.IO.FileAccess oder über eigens definierte.

Basics

Hier als einfaches Beispiel ein Enum, das die Benutzungsart einer Software beschreibt:

public enum UsageMode
{
    Private,
    Commercial,
    Education
}

und deren Verwendung in einer Klasse “Software”:

public class Software
{
    UsageMode usage = UsageMode.Commercial;
    public UsageMode Usage
    {
        get { return usage; }
        set { usage = value; }
    }
}

Enums sind im Prinzip nichts anderes, als benannte Konstanten für Integer-Werte. Im Beispiel werden die Werte wie folgt implizit durchnummeriert.

public enum UsageMode
{
    Private = 0,
    Commercial = 1,
    Education = 2
}

Dies lässt sich durch die schlichte Zuweisung eines beliebigen Integers aber ändern.

Dadurch, dass Enums neben benannten Konstanten eben auch numerische Werte darstellen, eignen sie sich auch sehr gut, um auf Arrays zu mappen.

public class Software
{
    UsageMode usage = UsageMode.Commercial;

    string[] humanText = new string[]
        {
            "Private (non-commercial) usage",
            "Unlimited commercial usage",
            "Educational usage"
        };

    public UsageMode Usage
    {
        get { return usage; }
        set { usage = value; }
    }

    public string HumanText
    {
        get { return humanText[(int)usage]; }
    }
}

Hier wird also eine Enumeration benutzt, um einen strukturierten Zugriff auf das String-Array humanText zu ermöglichen.

Wenns mal etwas mehr sein soll

Was nun aber, wenn ein Int32 für die gewünschten Datentypen nicht mehr ausreicht? Kein Problem, der zugrundeliegende Typ einer Enum kann über Vererbung geändert werden. So lässt sich eine Enum problemlos mit einem Int64 (long) verwenden:

public enum UsageMode : long
{
    Private = 2147483640L,
    Commercial = 2147483641L,
    Education = 2147483642L
}

Es liegt auf der Hand, dass dies nur in sehr speziellen Fällen notwendig ist – kann aber trotzdem sehr nützlich sein, wenn es zum Beispiel darum geht, Zahlen > 2^31 über benannnte Konstanten zugänglich zu machen.

Bit-Flags

Bis jetzt sind wir immer davon ausgegangen, dass sich die einzelnen Enumerationswerte ausschliessen. Nicht selten jedoch, sollen sich die Werte auch kombinieren lassen. So ist es durchaus vorstellbar, dass eine Software zu privaten wie auch kommerziellen Zwecken eingesetzt wird.

Dies lässt sich erreichen, indem man für die einzelne Werte auschliesslich Potenzen von 2 verwendet:

public enum UsageMode
{
    Private = 1,    // 2^0
    Commercial = 2, // 2^1
    Education = 4   // 2^2
}

Nun, wieso denn das? Wenn man sich dann die Verwendung anschaut, wird auch das klar:

usage = UsageMode.Commercial | UsageMode.Private;

Die beiden Werte werden also mit einem | (OR) verbunden. Wenn man dies nun auf die Zahlenwerte überträgt

1 OR 2 = 3

sieht man, dass die Kombination einen Zahlenwert ergibt, die in der Enum nicht vorkommt und eindeutig diesem Paar zugewiesen werden kann.

Und das ist natürlich notwendig, da man ja den Wert der Enum auch abfragen will:

bool isPrivateUsage = (UsageMode.Private & usage) == UsageMode.Private;

Man ANDet also den aktuellen Wert (usage) mit dem zu prüfenden Wert (UsageMode.Private). Oder in Zahlen ausgedrückt:

1 AND 3 = 1

Nun liegt es natürlich nahe, dass man für die 3 hier auch einen Enum-Wert einführen könnte, zum Beispiel “PrivateAndCommercial”, dies würde die Benützung vereinfachen, da zur Abfrage bzw. Aktivierung nicht jedes mal mit Bit-Operatoren hantiert werden müsste. Solche Kombinationen sollte man einführen, sofern sie gebräuchlich sind.

Oftmals wird auch ein Wert benötigt, der indiziert, dass keiner der Werte aktiviert wurde. Dieser (und nur dieser!) sollte dann jeweils mit der Zahl 0 versehen werden.

 
[System.Flags()]
public enum UsageMode
{
    None = 0,
    Private = 1,
    Commercial = 2,
    PrivateAndCommercial = 3,
    Education = 4
}

System.Flags-Attribut

Hier wurde nun noch das System.Flags-Attribut eingeführt. Dieses ist zwar nicht unbedingt notwendig für dieses Verhalten, ist jedoch empfehlenswert. Einfluss hat das Attribut zum Beispiel auf die Ausgabe des Enum-Wertes über die ToString()-Methode:

usage = UsageMode.Private | UsageMode.Commercial;
Console.WriteLine(usage.ToString()); // Ausgabe mit Flags: PrivateAndCommercial; Ausgabe ohne Flags: PrivateAndCommercial
usage = UsageMode.Private | UsageMode.Education;
Console.WriteLine(usage.ToString()); // Ausgabe mit Flags: Private, Commercial; Ausgabe ohne Flags: 3

Die kombinierten Werte werden also bei gesetztem Flags-Attribut mit Kommata getrennt, statt einfach als Zahl, ausgegeben. Dies kann sehr nützlich sein. So kann man zum Beispiel über die Split-Funktion von String so die einzelnen Werte sehr einfach in ein Array überführen.

Fazit

Enums bieten also ein sehr einfaches und flexibles Werkzeug, um mit Konstanten Werten zu hantieren. Gerade Anfänger lassen sich zu gerne von der Flags-Funktion abschrecken, da sie so sehr nach “Bits rumschieben” schmeckt. Die Beispiele zeigen jedoch, dass die Anwendung denkbar einfach und dafür umso Leistungsfähiger ist.

Hier noch zwei interessante Links in diesem Zusammenhang:
Enum Design-Guidelines von Krzysztof Cwalina
MSDN (C#)

Tags: ,

Aktuelle Zeilennummer ermitteln

August 17th, 2006 No comments

Gerade für’s Tracing / Logging ist man darauf angewiesen, zur Laufzeit Informationen darüber zu erhalten, wo man sich im Code gerade befindet – und zwar nicht nur wenn eine Exception geworfen wird.

Klassenname, Methodenname und ähnliches kriegt man ja problemlos über Reflection:

   1:  string method = System.Reflection.MethodInfo.GetCurrentMethod().Name;

Meist reicht dies – nützlicher wäre es allerdings, wenn man auch noch gleich die Zeilennummer erhalten könnte. Die Klasse StackFrame aus dem System.Diagnostics-Namespace bietet hierfür die nötigen Mittel:

   1:  StackFrame sf = new StackFrame( 1, true );
   2:  string methodName = sf.GetMethod().ToString();
   3:  string fileName = sf.GetFileName();
   4:  int lineNumber = sf.GetFileLineNumber();

In diesem Beispiel werden die Informationen aus dem letzten Stack-Eintrag ausgelesen (daher das 1 im Constructor). Das heisst, man erhält die Informationen über die Zeile, die die aktuelle Methode aufgerufen hat. Um die Informationen zum aktuellen Stack-Eintrag zu erhalten, initialisiert man die StackFrame-Klasse einfach mit 0.

Tags: , ,

C# 2.0 – Iteratoren

July 26th, 2006 No comments

Es gibt ja doch die eine oder andere spannende Neuerung in C# 2.0 – allen voran natürlich Generics.
Ebenfalls durchaus nützlich sind die neuen Iteratoren.

Was war…
Die foreach-Schleife gehörte auch schon in C# 1.0 zu den beliebtesten Schleifen-Typen. Um diese
auf eigene Datentypen anwenden zu können, wurde überlicherweise das IEnumerable-Interface implementiert werden;
dies sah dann so ähnlich aus:

public class BuddyList : IEnumerable{    string[] _buddies = { "Patrick", "Joel", "Daniel", "Andrea" };

    #region IEnumerable-Members

    public IEnumerator GetEnumerator()    {        return new BuddyEnumerator(this);    }

    #endregion    

    class BuddyEnumerator : IEnumerator    {        BuddyList _buddyList;        int _current;

        public BuddyEnumerator(BuddyList buddyList)        {            _buddyList = buddyList;            _current = -1;        }

        #region IEnumerator-Members

        void IEnumerator.Reset()        {            _current = -1;        }

        void IEnumerator.MoveNext()        {            return (++_current < _buddyList.Length);        }

        object IEnumeratorCurrent        {            get
            {
                if(_current == -1)                    throw new InvalidOperationException();                return _buddyList[_current];            }        }

        #endregion
    }
}

Also – eine Klasse BuddyList, die das Interface IEnumerable implementiert. IEnumerable verlangt nach der Methode
“GetEnumerator” welche wiederum eine IEnumerator-Implementation zurückgibt – und das ist genau, was die foreach-Schleife
benötigt, um funktionieren zu können.
Die IEnumerator-Implementation wurde hier in einer geschachtelten Klasse BuddyEnumerator implementiert. Verlangt
werden die Methoden Reset() und MoveNext() sowie das Property Current. Offensichtlich nicht sehr kompliziert, aber doch
einen ganzen Haufen an Code (und potenziellen Fehlern) für eine eigentlich so einfache Sache.


Schöne neue Welt!

C# 2.0 bietet hier eine viel einfachere und elegantere Methode, um dieses Unterfangen zu realisieren. Voraus gleich der Code:

public class BuddyList : IEnumerable<string>
{
    string[] _buddies = { "Patrick", "Joel", "Daniel", "Andrea" };

    #region IEnumerable Members

    IEnumerator<string> IEnumerable<string>.GetEnumerator()    {        for (int i = 0; i < _buddies.Length; i++)        {            yield return _buddies[i];        }    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<string>) this).GetEnumerator();    }

    #endregion
}

Das sieht doch schon etwas übersichtlicher aus. Wiederum wird also das Interface IEnumerable implementiert
(das hier das generische Pendant benutzt wird, tut nichts zur Sache). In der ersten GetEnumerator-Methode fällt
die Anweisung “yield” sofort ins Auge. Diese erzeugt für uns quasi automatisch die geschachtelte Klasse aus dem
C# 1.0-Beispiel.
Damit wird der Code viel übersichtlicher und weniger aufgebläht als mit den ganzen IEnumerator-Implementierungen.

Es ist auch möglich, laufende Iterationen zu unterbrechen – hierfür wird die Anweisung “yield break;” verwendet:

IEnumerator<string> IEnumerable<string>.GetEnumerator(){    for (int i = 0; i < _buddies.Length; i++)    {        yield return _buddies[i];

        // zeige nur 4 buddies
        if(i > 3)          yield break;    }}

Die kleine Beispiel-Applikation gibts zum download: Iterator.zip (582,07 KB)

Tags: , ,

String.Format – “{” escapen

March 25th, 2006 No comments

Wenn man auf einen String mit “{” drin String.Format anwenden will, kann man die geschweiften Klammern einfach verdoppeln – so werden sie quasi escaped.

string myStr = “Ein String mit {{ und {0}”;
string formattedStr = string.format(myStr, “Platzhalter”);

Gefunden bei Brad Abrams’ String.Format-FAQ

Tags: ,

Predicate

March 24th, 2006 No comments

Seit .NET 2.0 gibts auf den List- und Array-Klassen so praktische FindXY()-Methoden.

Diese Methoden erwarten alle einen Predicate<> – Parameter…

und so gehts:

List<MyType> lstT = new List<MyType>();for (int i = 0; i < 100; i++){   lstT.Add(new MyType(i.ToString(), i));}

string searchExpr = "20";

lstT.Find(   delegate(MyType obj)   {       return searchExpr == obj.Test1;   });

Das ganze wurde hier mit anonymen Methoden gelöst – das muss natürlich nicht sein, haltet das ganze aber einfach.

Tags: ,

BigInteger

March 22nd, 2006 1 comment

http://www.codeproject.com/csharp/biginteger.asp

Damit kann man zB. sehr einfach mit 128Bit-Werten nummerisch rechnen.

Beispiel (zwei 128-Bit Hex-Werte addieren):
BigInteger b1 = new BigInteger(“80438539FF328345983A245E59000000″, 16);
BigInteger b2 = new BigInteger(“80438539F4568345983A245E59000000″, 16);

string result = ((BigInteger)(b1 + b2).ToHexString();

Tags: ,
Sharing Buttons by Linksku