Freigeben über


Fortgeschrittene C#-Techniken (C# und Java im Vergleich)

Aktualisiert: November 2007

C# stellt einige nützliche Sprachfeatures bereit, z. B. Indexer, Attribute und Delegaten, die erweiterte Programmierverfahren ermöglichen.

Indexer

Indexer bieten die Möglichkeit, auf class oder struct in derselben Weise wie auf ein Array zuzugreifen. Zum Beispiel können Sie über eine Klasse verfügen, die eine einzelne Abteilung in einer Firma darstellt. Die Klasse könnte die Namen aller Mitarbeiter der Abteilung enthalten, und mit den Indexern könnten Sie wie folgt auf die Namen zugreifen:

sales[0] = "Nikki";
sales[1] = "Becky";

Indexer werden durch die Definition einer Eigenschaft mit der folgenden Signatur aktiviert, z. B. in der Klassendefinition:

public string this [int index]  //indexer

Anschließend stellen Sie wie für eine normale Eigenschaft eine get-Methode und eine set-Methode bereit. Diese Accessoren geben bei Verwendung der Indexer an, auf welche internen Member verwiesen wird.

Im folgenden einfachen Beispiel erstellen Sie eine Klasse mit dem Namen Department. Diese Klasse verwendet Indexer, um auf die Mitarbeiter dieser Abteilung zuzugreifen. Die Mitarbeiter werden intern als ein Array von Zeichenfolgen dargestellt.

public class Department
{
    private string name;
    private const int MAX_EMPLOYEES = 10;
    private string[] employees = new string[MAX_EMPLOYEES];  //employee array

    public Department(string departmentName)  //constructor
    {
        name = departmentName;
    }

    public string this [int index]  //indexer
    {
        get
        {
            if (index >= 0 && index < MAX_EMPLOYEES)
            {
                return employees[index];
            }
            else
            {
                throw new System.IndexOutOfRangeException();
            }
        }
        set
        {
            if (index >= 0 && index < MAX_EMPLOYEES)
            {  
                employees[index] = value;
            }
            else
            {
                throw new System.IndexOutOfRangeException();
            }
        }
    }

    // code for the rest of the class...
}

Sie können dann eine Instanz dieser Klasse erstellen und darauf wie im folgenden Codebeispiel zugreifen:

class TestDepartment
{
    static void Main()
    {
        Department sales = new Department("Sales");

        sales[0] = "Nikki";
        sales[1] = "Becky";

        System.Console.WriteLine("The sales team is {0} and {1}", sales[0], sales[1]);
    }
}

Die Ausgabe lautet:

The sales team is Nikki and Becky

Weitere Informationen hierzu finden Sie unter Indexer (C#-Programmierhandbuch).

Attribute

C# stellt einen Mechanismus namens Attribut zum Hinzufügen von deklarativen Informationen über Typen bereit. Attribute sind in gewisser Hinsicht mit dem Konzept von Anmerkungen in Java vergleichbar. Zusätzliche Informationen über einen Typ werden in deklarativen Tags platziert, die der Typdefinition vorangestellt werden. In den folgenden Beispielen wird veranschaulicht, wie Sie eine Klasse oder Methode mit .NET Framework-Attributen ergänzen können.

Im folgenden Beispiel wird die GetTime-Methode durch das Hinzufügen des WebMethodAttribute-Attributs als XML-Webdienst markiert.

public class Utilities : System.Web.Services.WebService
{
    [System.Web.Services.WebMethod]  // Attribute
    public string GetTime()
    {
        return System.DateTime.Now.ToShortTimeString();
    }
}

Durch das Hinzufügen des WebMethod-Attributs sorgt .NET Framework automatisch für den XML/SOAP-Austausch, der zum Aufrufen dieser Funktion notwendig ist. Durch das Aufrufen dieses Webdiensts wird der folgenden Wert abgerufen:

<?xml version="1.0" encoding="utf-8" ?>

<string xmlns="http://tempuri.org/">7:26 PM</string>

Im folgenden Beispiel wird die Employee-Klasse durch Hinzufügen des SerializableAttribute-Attributs als serialisierbar markiert. Das Salary-Feld ist als public gekennzeichnet. Es wird jedoch nicht serialisiert, da es mit dem NonSerializedAttribute-Attribut gekennzeichnet ist.

[System.Serializable()]        
public class Employee  
{
    public int ID;
    public string Name;        
    [System.NonSerialized()] public int Salary; 
}

Weitere Informationen hierzu finden Sie unter Erstellen benutzerdefinierter Attribute (C#-Programmierhandbuch).

Delegaten

Programmiersprachen wie C++, Pascal und andere unterstützen das Konzept von Funktionszeigern. Mit diesen können Sie auswählen, welche Funktion Sie zur Laufzeit aufrufen möchten.

Java stellt kein Konstrukt mit der Funktionalität eines Funktionszeigers bereit, C# allerdings schon. Durch die Verwendung der Delegate-Klasse kapselt eine delegate-Instanz eine Methode, die eine aufrufbare Entität ist.

Bei Instanzenmethoden besteht der Delegat aus einer Instanz der enthaltenden Klasse und einer Methode für die Instanz. Bei statischen Methoden besteht eine aufrufbare Entität aus einer Klasse und einer statischen Methode für die Klasse. Folglich kann mit einem Delegaten eine Funktion eines beliebigen Objekts aufgerufen werden. Delegaten sind objektorientiert, typsicher und sicher.

Es gibt drei Schritte für das Definieren und Verwenden von Delegaten:

  • Deklaration

  • Instanziierung

  • Aufruf

Delegaten werden mit der folgenden Syntax deklariert:

delegate void Del1();

Mit diesem Delegaten kann dann auf alle Funktionen verwiesen werden, die void zurückgeben und keine Argumente akzeptieren.

Verwenden Sie die folgende Syntax, um auf ähnliche Weise einen Delegaten für alle Funktionen zu erstellen, die einen Zeichenfolgenparameter annehmen und long zurückgeben.

delegate long Del2(string s);

Sie könnten dann diesen Delegaten jeder Methode mit dieser Signatur zuweisen:

Del2 d;                // declare the delegate variable
d = DoWork;  // set the delegate to refer to the DoWork method

Wobei die Signatur von DoWork wie folgt lautet:

public static long DoWork(string name)

Neuzuweisung von Delegaten

Delegate-Objekte sind unveränderlich. Das heißt, dass die Signatur, mit der sie übereinstimmen, nach dem Festlegen nicht mehr verändert werden kann. Sie können jedoch auf eine andere Methode zeigen, solange beide die gleiche Signatur haben. In diesem Beispiel wird d einem neuen Delegatobjekt zugewiesen, sodass d die DoMoreWork-Methode aufruft. Dies ist nur möglich, wenn DoWork und DoMoreWork dieselbe Signatur besitzen.

Del2 d;                    // declare the delegate variable
d = DoWork;      // set the delegate to refer to the DoWork method
d = DoMoreWork;  // reassign the delegate to refer to the DoMoreWork method

Aufrufen von Delegaten

Das Aufrufen von Delegaten ist ganz einfach. Sie ersetzen einfach den Namen der Delegatvariablen durch den Methodennamen. Dadurch wird die Add-Methode mit den Werten 11 und 22 aufgerufen. Dann wird ein long-Ergebnis zurückgegeben, das der sum-Variable zugewiesen wird:

Del operation;                 // declare the delegate variable
operation = Add;      // set the delegate to refer to the Add method
long sum = operation(11, 22);  // invoke the delegate

Der folgende Code veranschaulicht die Erstellung, die Instanziierung und den Aufruf eines Delegaten:

public class MathClass
{
    public static long Add(int i, int j)       // static
    {
        return (i + j);
    }

    public static long Multiply (int i, int j)  // static
    {
        return (i * j);
    }
}

class TestMathClass
{
    delegate long Del(int i, int j);  // declare the delegate type

    static void Main()
    {
        Del operation;  // declare the delegate variable

        operation = MathClass.Add;       // set the delegate to refer to the Add method
        long sum = operation(11, 22);             // use the delegate to call the Add method

        operation = MathClass.Multiply;  // change the delegate to refer to the Multiply method
        long product = operation(30, 40);         // use the delegate to call the Multiply method

        System.Console.WriteLine("11 + 22 = " + sum);
        System.Console.WriteLine("30 * 40 = " + product);
    }
}

Ausgabe

11 + 22 = 33

30 * 40 = 1200

Eine Delegatinstanz muss einen Objektverweis enthalten. Im vorherigen Beispiel wird dies durch das Deklarieren der Methoden als static umgangen. Somit besteht keine Notwendigkeit, einen Objektverweis anzugeben. Wenn ein Delegat jedoch auf eine Instanzenmethode verweist, muss der Objektverweis jedoch wie folgt angegeben werden:

Del operation;                   // declare the delegate variable
MathClass m1 = new MathClass();  // declare the MathClass instance
operation = m1.Add;     // set the delegate to refer to the Add method

In diesem Beispiel sind Add und Multiply Instanzmethoden von MathClass. Wenn die Methoden von MathClass nicht als statisch deklariert werden, rufen Sie sie mithilfe einer Instanz von MathClass wie folgt über den Delegaten auf:

public class MathClass
{
    public long Add(int i, int j)       // not static
    {
        return (i + j);
    }

    public long Multiply (int i, int j)  // not static
    {
        return (i * j);
    }
}

class TestMathClass
{
    delegate long Del(int i, int j);  // declare the delegate type

    static void Main()
    {
        Del operation;                   // declare the delegate variable
        MathClass m1 = new MathClass();  // declare the MathClass instance

        operation = m1.Add;       // set the delegate to refer to the Add method
        long sum = operation(11, 22);      // use the delegate to call the Add method

        operation = m1.Multiply;  // change the delegate to refer to the Multiply method
        long product = operation(30, 40);  // use the delegate to call the Multiply method

        System.Console.WriteLine("11 + 22 = " + sum);
        System.Console.WriteLine("30 * 40 = " + product);
    }
}

Ausgabe

In diesem Beispiel wird die gleiche Ausgabe wie im vorherigen Beispiel erhalten, in dem die Methoden als static deklariert wurden.

11 + 22 = 33

30 * 40 = 1200

Delegaten und Ereignisse

.NET Framework verwendet Delegaten auch ausgiebig für Ereignisbehandlungsaufgaben wie Klickereignisse einer Schaltfläche in Windows- oder Webanwendungen. Während die Ereignisbehandlung in Java normalerweise durch die Implementierung benutzerdefinierter Listenerklassen erfolgt, können sich C#-Entwickler die Vorteile bei der Verwendung von Delegaten für die Ereignisbehandlung zunutze machen. Ein event wird wie ein Feld mit einem Delegattyp deklariert, mit der Ausnahme, dass das Schlüsselwortereignis der Ereignisdeklaration vorangeht. Ereignisse werden normalerweise als public deklariert. Es sind jedoch alle Zugriffsmodifizierer zulässig. Im folgenden Beispiel wird die Deklaration eines delegate und eines event gezeigt.

// Declare the delegate type:
public delegate void CustomEventHandler(object sender, System.EventArgs e);

// Declare the event variable using the delegate type:
public event CustomEventHandler CustomEvent;

Ereignisdelegaten sind Multicastdelegaten, d. h., sie können Verweise auf mehrere Methoden für die Ereignisbehandlung enthalten. Ein Delegat fungiert als ein Ereignisverteiler für die Klasse, die das Ereignis auslöst, indem er eine Liste der registrierten Ereignishandler für das Ereignis verwaltet. Im folgenden Beispiel wird veranschaulicht, wie Sie ein Ereignis für mehrere Funktionen abonnieren können. Die EventClass-Klasse enthält den Delegaten, das Ereignis und eine Methode, um das Ereignis aufzurufen. Beachten Sie, dass ein Ereignis nur innerhalb der Klasse aufgerufen werden kann, die es deklariert hat. Die TestEvents-Klasse kann dann das Ereignis mit dem Operator += abonnieren und mit dem Operator -= das Abonnement kündigen. Wenn die InvokeEvent-Methode aufgerufen wird, löst sie das Ereignis aus. Alle Funktionen, die das Ereignis abboniert haben, lösen dann gleichzeitig aus, wie im folgenden Beispiel gezeigt.

public class EventClass
{
    // Declare the delegate type:
    public delegate void CustomEventHandler(object sender, System.EventArgs e);

    // Declare the event variable using the delegate type:
    public event CustomEventHandler CustomEvent;

    public void InvokeEvent()
    {
        // Invoke the event from within the class that declared the event:
        CustomEvent(this, System.EventArgs.Empty);
    }
}

class TestEvents
{
    private static void CodeToRun(object sender, System.EventArgs e)
    {
        System.Console.WriteLine("CodeToRun is executing");
    }

    private static void MoreCodeToRun(object sender, System.EventArgs e)
    {
        System.Console.WriteLine("MoreCodeToRun is executing");
    }

    static void Main()
    {
        EventClass ec = new EventClass();

        ec.CustomEvent += new EventClass.CustomEventHandler(CodeToRun);
        ec.CustomEvent += new EventClass.CustomEventHandler(MoreCodeToRun); 

        System.Console.WriteLine("First Invocation:");
        ec.InvokeEvent();

        ec.CustomEvent -= new EventClass.CustomEventHandler(MoreCodeToRun);

        System.Console.WriteLine("\nSecond Invocation:");
        ec.InvokeEvent();
    }
}

Ausgabe

First Invocation:

CodeToRun is executing

MoreCodeToRun is executing

Second Invocation:

CodeToRun is executing

Siehe auch

Aufgaben

Beispiel für Delegaten

Konzepte

C#-Programmierhandbuch

Referenz

Delegaten (C#-Programmierhandbuch)

Ereignisse (C#-Programmierhandbuch)

Weitere Ressourcen

Die Programmiersprache C# für Java-Entwickler