Galileo Computing <openbook>
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


C# von Eric Gunnerson
Die neue Sprache für Microsofts .NET-Plattform
C# - Zum Katalog
gp Kapitel 24 Ereignisse
  gp 24.1 Ein Ereignis zu einer neuen E-Mail-Nachricht
  gp 24.2 Das Ereignisfeld
  gp 24.3 Multicastereignisse
  gp 24.4 Selten verwendete Ereignisse

Kapitel 24 Ereignisse

Eine Klasse kann ein Ereignis dazu verwenden, eine andere Klasse (oder andere Klassen) über ein aufgetretenes Ereignis zu benachrichtigen. Ereignisse verwenden das Veröffentlichen-Abonnieren-Prinzip; eine Klasse veröffentlicht die Ereignisse, die sie ausgeben kann, und Klassen, die Interesse an bestimmten Ereignissen haben, können diese Ereignisse abonnieren.

Ereignisse werden in grafischen Benutzerschnittstellen häufig dazu eingesetzt, über eine Benutzerauswahl zu informieren, sie eignen sich jedoch auch für asynchrone Operationen, beispielsweise für Dateiänderungen oder das Empfangen von E-Mail-Nachrichten.

Die Routine, mit der ein Ereignis aufgerufen wird, wird durch eine Zuweisung (delegate) definiert. Zur einfacheren Handhabung von Ereignissen legen die Entwurfskonventionen für Ereignisse fest, dass die Zuweisung immer zwei Parameter umfasst. Der erste Parameter bezeichnet das Objekt, durch das das Ereignis ausgelöst wurde, der zweite Parameter ist ein Objekt, das Informationen zum Ereignis enthält. Dieses Objekt leitet sich immer von der EventArgs-Klasse ab.


Galileo Computing

24.1 Ein Ereignis zu einer neuen E-Mail-Nachricht  downtop

Hier ein Beispiel zu Ereignissen.

using System;
class NewEmailEventArgs: EventArgs
{
    public NewEmailEventArgs(string subject, string message)
    {
        this.subject = subject;
        this.message = message;
    }
    public string Subject
    {
        get
        {
            return(subject);
        }
    }
    public string Message
    {
        get
        {
            return(message);
        }
    }
    string subject;
    string    message;
}
class EmailNotify
{
    public delegate void NewMailEventHandler(object sender,
        NewEmailEventArgs e);
    public event NewMailEventHandler    OnNewMailHandler;

    protected void OnNewMail(NewEmailEventArgs e)
    {
        if (OnNewMailHandler != null)
            OnNewMailHandler(this, e);
    }
    public void NotifyMail(string subject, string message)
    {
        NewEmailEventArgs e = new NewEmailEventArgs(subject, message);
        OnNewMail(e);
    }
}
class MailWatch
{
    public MailWatch(EmailNotify emailNotify)
    {
        this.emailNotify = emailNotify;
        emailNotify.OnNewMailHandler +=
            new EmailNotify.NewMailEventHandler(IHaveMail);
    }
    void IHaveMail(object sender, NewEmailEventArgs e)
    {
        Console.WriteLine("New Mail: {0}\n{1]",
                    e.Subject, e.Message);
    }
    EmailNotify    emailNotify;
}
class Test
{
    public static void Main()
    {
        EmailNotify emailNotify = new EmailNotify();
        MailWatch mailWatch = new MailWatch(emailNotify);
        emailNotify.NotifyMail("Hello!", "Welcome to Events!!!");
    }
}

Die NewEMailEventArgs-Klasse enthält die Informationen, die bei der Ausgabe eines NewEmail-Ereignisses übergeben werden.

Die EMailNotify-Klasse ist für die Ereignishandhabung verantwortlich; über diese Klasse wird die Zuweisung deklariert, mit der definiert wird, welche Parameter bei Auftreten des Ereignisses übergeben werden. Des Weiteren enthält die Klasse eine Definition des Ereignisses selbst. Die OnNewMail()-Funktion wird zur Ausgabe des Ereignisses eingesetzt, die Helferfunktion NotifyMail() enthält die Ereignisinformationen, packt diese in eine Instanz von NewEmailEventArgs und ruft OnNewMail() zur Ereignisausgabe auf.

Die Klasse MailWatch ist ein Konsument der EmailNotify-Klasse. Sie übernimmt eine Instanz der EmailNotify-Klasse und koppelt die IHaveMail()-Funktion an das OnNewMailHandler-Ereignis.

Abschließend erstellt die Main()-Funktion Instanzen von EmailNotify und MailWatch und ruft die Funktion NotifyMail() zur Ereignisausgabe auf.


Galileo Computing

24.2 Das Ereignisfeld  downtop

Im vorangegangenen Beispiel lautet das Ereignisfeld EmailNotify.OnNewMailHandler. Innerhalb der Klasse, die das Ereignisfeld enthält, gelten für dessen Verwendung keine Einschränkungen.

Außerhalb der Deklaration von EmailNotify jedoch kann ein Ereignisfeld nur für die linke Seite der Operatoren += und -= eingesetzt werden; das Feld kann anderweitig weder untersucht noch geändert werden.


Galileo Computing

24.3 Multicastereignisse  downtop

C#-Ereignisse sind Multicastereignisse, d. h., beim Auslösen eines Ereignisses können mehrere Zuweisungen mit den Ereignisinformationen aufgerufen werden. Die Aufrufreihenfolge für Zuweisungen ist nicht definiert, und wenn eine Zuweisung eine Ausnahme auslöst, kann dies dazu führen, dass andere Zuweisungen nicht aufgerufen werden.


Galileo Computing

24.4 Selten verwendete Ereignisse  toptop

Die Mehrzahl der Klassen implementiert Ereignisse über Ereignisfelder, wie im vorangegangenen Beispiel gezeigt wurde. Werden durch eine Klasse zahlreiche Ereignisse implementiert, werden von diesen Ereignissen voraussichtlich jedoch nur wenige gleichzeitig eingesetzt (sparse events), stellt die Reservierung eines separaten Feldes für jedes Ereignis eine Verschwendung von Speicherplatz dar. Dies kann beispielsweise auf ein Benutzerschnittstellensteuerelement zutreffen, das viele Ereignisse unterstützt.

In dieser Situation kann eine Klasse anstelle von Ereignisfeldern Ereigniseigenschaften deklarieren und einen privaten Mechanismus zur Speicherung der zugrunde liegenden Zuweisungen verwenden. Nachfolgend wurde das obige Beispiel überarbeitet, anstelle von Ereignisfeldern werden Ereigniseigenschaften verwendet.

using System;
using System.Collections;
class NewEmailEventArgs: EventArgs
{
    public NewEmailEventArgs(string subject, string message)
    {
        this.subject = subject;
        this.message = message;
    }
    public string Subject
    {
        get
        {
            return(subject);
        }
    }
    public string Message
    {
        get
        {
            return(message);
        }
    }
    string subject;
    string    message;
}
class EmailNotify
{
    public delegate void NewMailEventHandler(object sender,
        NewEmailEventArgs e);

    protected Delegate GetEventHandler(object key)
    {
        return((Delegate) handlers[key]);
    }
    protected void SetEventHandler(object key, Delegate del)
    {
        handlers.Add(key, del);
    }

    public event NewMailEventHandler    OnNewMailHandler
    {
        get
        {
            return((NewMailEventHandler)
            GetEventHandler(onNewMailKey));
        }
        set
        {
            SetEventHandler(onNewMailKey, value);
        }
    }

    public void OnNewMail(NewEmailEventArgs e)
    {
        if (OnNewMailHandler != null)
            OnNewMailHandler(this, e);
    }
    public void NotifyMail(string subject, string message)
    {
        NewEmailEventArgs e = new NewEmailEventArgs(subject, message);
        OnNewMail(e);
    }
    Hashtable    handlers = new Hashtable();
        // Eindeutiger Schlüssel für dieses Ereignis
    static readonly object onNewMailKey = new object();
}
class MailWatch
{
    public MailWatch(EmailNotify emailNotify)
    {
        this.emailNotify = emailNotify;
        emailNotify.OnNewMailHandler +=
        new EmailNotify.NewMailEventHandler(IHaveMail);
    }
    void IHaveMail(object sender, NewEmailEventArgs e)
    {
        Console.WriteLine("New Mail: {0}\n{1]",
                    e.Subject, e.Message);
    }
    EmailNotify    emailNotify;
}
class Test
{
    public static void Main()
    {
        EmailNotify emailNotify = new EmailNotify();
        MailWatch mailWatch = new MailWatch(emailNotify);
        emailNotify.NotifyMail("Hello!", "Welcome to Events!!!");
    }
}

Die EmailNotify-Klasse verfügt nun anstelle eines gleichnamigen Ereignisses über eine Eigenschaft namens NewMailEventHandler. Die Eigenschaft speichert die Zuweisung in einer Hashtabelle (statt diese in einem Ereignisfeld zu platzieren) und stellt mit dem statischen, schreibgeschützten Objekt onNewMailKey sicher, dass die Eigenschaft die geeignete Zuweisung auffindet. Da garantiert eindeutige Objektverweise über das System bereitgestellt werden, kann durch das Erzeugen eines statischen, schreibgeschützten Objekts zur Laufzeit ein eindeutiger Schlüssel generiert werden.

In dieser Situation wäre die Verwendung einer Hashtabelle jedoch unangemessen, da mehr Speicherplatz als bei der vorherigen Version belegt wird. Diese Vorgehensweise eignet sich eher für Objekthierarchien – beispielsweise für Steuerelemente, die von der Basisklasse Control abgeleitet werden – mit vielen selten verwendeten Ereignissen (sparse events). Die Control-Klasse implementiert GetEventHandler() und SetEventHandler(). Alle Steuerelemente, die von der Klasse abgeleitet werden, können hierüber die vorhandenen Zuweisungen speichern.

Beachten Sie, dass dies nur ein Vorteil ist, wenn voraussichtlich mehrere Instanzen jedes Steuerelements gleichzeitig vorhanden sind. Ist dies nicht der Fall, überwiegt das Mehr an Speicherplatz für den statischen, schreibgeschützten Schlüssel gegenüber den Einsparungen im Objekt.

   

Select * from SQL Server 2000




Copyright © Galileo Press GmbH 2001 - 2002
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, fon: 0228.42150.0, fax 0228.42150.77, info@galileo-press.de