Was sind die Unterschiede zwischen Delegierten und Veranstaltungen?

Antworten:

280

Eine Ereignisdeklaration fügt der Delegateninstanz eine Ebene der Abstraktion und des Schutzes hinzu . Dieser Schutz verhindert, dass Clients des Delegaten den Delegaten und seine Aufrufliste zurücksetzen, und ermöglicht nur das Hinzufügen oder Entfernen von Zielen zur Aufrufliste.

mmcdole
quelle
43
Natürlich verhindert diese Schutzschicht auch, dass "Clients" (Code außerhalb der definierenden Klasse / Struktur) den Delegaten aufrufen und das Delegatenobjekt "hinter" dem Ereignis in irgendeiner Weise erhalten.
Jeppe Stig Nielsen
7
Nicht ganz richtig. Sie können ein Ereignis ohne eine Backend-Delegateninstanz deklarieren. In c # können Sie ein Ereignis explizit implementieren und eine andere Backend-Datenstruktur Ihrer Wahl verwenden.
Miguel Gamboa
3
@mmcdole kannst du ein Beispiel geben, um seine zu erklären?
Vivek Nuna
102

Um die Unterschiede zu verstehen, können Sie sich diese beiden Beispiele ansehen

Beispiel mit Delegaten (in diesem Fall eine Aktion - das ist eine Art Delegat, der keinen Wert zurückgibt)

public class Animal
{
    public Action Run {get; set;}

    public void RaiseEvent()
    {
        if (Run != null)
        {
            Run();
        }
    }
}

Um den Delegaten zu verwenden, sollten Sie Folgendes tun:

Animal animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();

Dieser Code funktioniert gut, aber Sie könnten einige Schwachstellen haben.

Zum Beispiel, wenn ich das schreibe:

animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;

Mit der letzten Codezeile habe ich die vorherigen Verhaltensweisen nur mit einem fehlenden überschrieben +(ich habe =statt verwendet +=)

Eine weitere Schwachstelle ist, dass jede Klasse, die Ihre AnimalKlasse verwendet, RaiseEventnur einen Aufruf auslösen kann animal.RaiseEvent().

Um diese Schwachstellen zu vermeiden, können Sie eventsin c # verwenden.

Ihre Tierklasse ändert sich folgendermaßen:

public class ArgsSpecial : EventArgs
{
    public ArgsSpecial (string val)
    {
        Operation=val;
    }

    public string Operation {get; set;}
} 

public class Animal
{
    // Empty delegate. In this way you are sure that value is always != null 
    // because no one outside of the class can change it.
    public event EventHandler<ArgsSpecial> Run = delegate{} 

    public void RaiseEvent()
    {  
         Run(this, new ArgsSpecial("Run faster"));
    }
}

Ereignisse aufrufen

 Animal animal= new Animal();
 animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
 animal.RaiseEvent();

Unterschiede:

  1. Sie verwenden keine öffentliche Eigenschaft, sondern ein öffentliches Feld (mithilfe von Ereignissen schützt der Compiler Ihre Felder vor unerwünschtem Zugriff).
  2. Ereignisse können nicht direkt zugewiesen werden. In diesem Fall wird der vorherige Fehler, den ich beim Überschreiben des Verhaltens gezeigt habe, nicht verursacht.
  3. Niemand außerhalb Ihrer Klasse kann das Ereignis auslösen.
  4. Ereignisse können in eine Schnittstellendeklaration aufgenommen werden, ein Feld jedoch nicht

Anmerkungen:

EventHandler wird als folgender Delegat deklariert:

public delegate void EventHandler (object sender, EventArgs e)

Es werden ein Absender (vom Objekttyp) und Ereignisargumente benötigt. Der Absender ist null, wenn er aus statischen Methoden stammt.

Dieses Beispiel, das verwendet EventHandler<ArgsSpecial>, kann EventHandlerstattdessen auch mit geschrieben werden .

Siehe hier für die Dokumentation über Eventhandler

Faby
quelle
7
Alles sah großartig aus, bis ich auf "Niemand außerhalb Ihrer Klasse kann das Ereignis auslösen" stieß. Was bedeutet das? Kann niemand aufrufen RaiseEvent, solange eine aufrufende Methode Zugriff auf eine Instanz des animalCodes hat, der das Ereignis verwendet?
Tanz2die
11
@Sung Events können nur innerhalb der Klasse ausgelöst werden, vielleicht habe ich das nicht klar erklärt. Bei Ereignissen können Sie die Funktion aufrufen, die das Ereignis auslöst (Kapselung), sie kann jedoch nur innerhalb der Klasse ausgelöst werden, die es definiert. Lassen Sie mich wissen, wenn ich nicht klar bin.
Faby
1
"Ereignisse können nicht direkt zugewiesen werden." Wenn ich dich nicht falsch verstehe, ist das nicht wahr. Hier ist ein Beispiel: gist.github.com/Chiel92/36bb3a2d2ac7dd511b96
Chiel ten Brinke
2
@faby, du meinst, obwohl das Ereignis als öffentlich deklariert ist, kann ich es immer noch nicht tun animal.Run(this, new ArgsSpecial("Run faster");?
Pap
1
@ChaltenBrinke Natürlich kann das Ereignis innerhalb von Mitgliedern der Klasse zugewiesen werden ... aber nicht anders.
Jim Balter
93

Neben den syntaktischen und operativen Eigenschaften gibt es auch einen semantischen Unterschied.

Delegierte sind konzeptionell Funktionsvorlagen. Das heißt, sie drücken einen Vertrag aus, den eine Funktion einhalten muss, um vom "Typ" des Delegierten zu sein.

Ereignisse repräsentieren ... nun, Ereignisse. Sie sollen jemanden alarmieren, wenn etwas passiert, und ja, sie halten sich an eine Delegiertendefinition, aber sie sind nicht dasselbe.

Selbst wenn sie genau dasselbe wären (syntaktisch und im IL-Code), bleibt der semantische Unterschied bestehen. Im Allgemeinen bevorzuge ich zwei unterschiedliche Namen für zwei unterschiedliche Konzepte, auch wenn sie auf dieselbe Weise implementiert sind (was nicht bedeutet, dass ich denselben Code zweimal haben möchte).

Jorge Córdoba
quelle
8
Hervorragende Beschreibung der Delegierten.
Sampson
1
Können wir also sagen, dass eine Veranstaltung ein "besonderer" Typ eines Delegierten ist?
Pap
Ich verstehe Ihren Standpunkt nicht. Sie können einen Delegierten verwenden, um "jemanden zu benachrichtigen, wenn etwas passiert". Vielleicht würden Sie das nicht tun, aber Sie können und deshalb ist es keine inhärente Eigenschaft des Ereignisses.
Steve
@Jorge Córdoba Beispiel für einen Delegierten und einen Delegierten für Veranstaltungen ist ein Zeitungsinhaber und für Veranstaltungen (Abonnieren oder Abbestellen). Einige Leute kaufen die Zeitung, andere kaufen die Zeitung nicht richtig oder falsch?
Rahul_Patil
37

Hier ist ein weiterer guter Link, auf den Sie verweisen können. http://csharpindepth.com/Articles/Chapter2/Events.aspx

Kurz gesagt, das Herausnehmen aus dem Artikel - Ereignisse sind Kapselung über Delegierte.

Zitat aus dem Artikel:

Angenommen, Ereignisse waren in C # /. NET nicht als Konzept vorhanden. Wie würde eine andere Klasse eine Veranstaltung abonnieren? Drei Optionen:

  1. Eine öffentliche Delegatenvariable

  2. Eine Delegatenvariable, die von einer Eigenschaft unterstützt wird

  3. Eine Delegatvariable mit den Methoden AddXXXHandler und RemoveXXXHandler

Option 1 ist eindeutig schrecklich, aus all den normalen Gründen verabscheuen wir öffentliche Variablen.

Option 2 ist etwas besser, ermöglicht es den Abonnenten jedoch, sich gegenseitig effektiv zu überschreiben. Es wäre allzu einfach, someInstance.MyEvent = eventHandler zu schreiben. Dies würde alle vorhandenen Ereignishandler ersetzen, anstatt einen neuen hinzuzufügen. Außerdem müssen Sie die Eigenschaften noch schreiben.

Option 3 ist im Grunde das, was Ereignisse Ihnen bieten, aber mit einer garantierten Konvention (vom Compiler generiert und durch zusätzliche Flags in der IL unterstützt) und einer "kostenlosen" Implementierung, wenn Sie mit der Semantik zufrieden sind, die feldähnliche Ereignisse Ihnen bieten. Das Abonnieren und Abbestellen von Ereignissen ist gekapselt, ohne dass ein willkürlicher Zugriff auf die Liste der Ereignishandler möglich ist. Sprachen können die Arbeit vereinfachen, indem sie die Syntax für Deklaration und Abonnement bereitstellen.

Vibhu
quelle
Schöne und prägnante Erklärung. Vielen Dank
Pap
Dies ist eher ein theoretisches Problem als alles andere, aber FWIW Ich hatte immer das Gefühl, dass das Argument "Option 1 ist schlecht, weil wir keine öffentlichen Variablen mögen" etwas mehr Klarheit gebrauchen könnte. Wenn er das sagt, weil es "schlechte OOP-Praxis" ist, würde eine Variable technisch gesehenpublic Delegate "Daten" offenlegen, aber nach meinem besten Wissen hat OOP niemals Konzepte wie ein erwähnt Delegate(es ist weder ein "Objekt" noch eine "Nachricht"). und .NET behandelt Delegierte sowieso kaum wie Daten.
jrh
Wenn Sie sich in einer Situation befinden, in der Sie sicherstellen möchten, dass es nur einen Handler gibt, kann es jedoch eine gute Option sein, eigene AddXXXHandlerMethoden mit einer private DelegateVariablen zu erstellen. In diesem Fall können Sie überprüfen, ob bereits ein Handler eingerichtet ist, und entsprechend reagieren. Dies kann auch eine gute Einrichtung sein, wenn Sie das Objekt benötigen, das das enthält Delegate, um alle Handler löschen zu können ( eventgibt Ihnen keine Möglichkeit, dies zu tun).
jrh
7

HINWEIS: Wenn Sie Zugriff auf C # 5.0 Unleashed haben , lesen Sie die "Einschränkungen für die einfache Verwendung von Delegaten" in Kapitel 18 mit dem Titel "Ereignisse", um die Unterschiede zwischen den beiden besser zu verstehen.


Es hilft mir immer, ein einfaches, konkretes Beispiel zu haben. Also hier ist eine für die Community. Zuerst zeige ich, wie Sie Delegierte alleine verwenden können, um das zu tun, was Events für uns tun. Dann zeige ich, wie dieselbe Lösung mit einer Instanz von funktionieren würde EventHandler. Und dann erkläre ich, warum wir NICHT das tun wollen, was ich im ersten Beispiel erkläre. Dieser Beitrag wurde von einem Artikel von John Skeet inspiriert .

Beispiel 1: Verwenden eines öffentlichen Delegaten

Angenommen, ich habe eine WinForms-App mit einer einzelnen Dropdown-Box. Das Dropdown ist an ein gebunden List<Person>. Wobei Person Eigenschaften von ID, Name, Spitzname, Haarfarbe hat. Auf dem Hauptformular befindet sich ein benutzerdefiniertes Benutzersteuerelement, das die Eigenschaften dieser Person anzeigt. Wenn jemand eine Person in der Dropdown-Liste auswählt, werden die Beschriftungen im Benutzersteuerelement aktualisiert, um die Eigenschaften der ausgewählten Person anzuzeigen.

Geben Sie hier die Bildbeschreibung ein

So funktioniert das Wir haben drei Dateien, die uns dabei helfen, dies zusammenzustellen:

  • Mediator.cs - statische Klasse enthält die Delegaten
  • Form1.cs - Hauptformular
  • DetailView.cs - Benutzersteuerung zeigt alle Details

Hier ist der relevante Code für jede der Klassen:

class Mediator
{
    public delegate void PersonChangedDelegate(Person p); //delegate type definition
    public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
    public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
    {
        if (PersonChangedDel != null)
        {
            PersonChangedDel(p);
        }
    }
}

Hier ist unsere Benutzersteuerung:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.PersonChangedDel += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(Person p)
    {
        BindData(p);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

Schließlich haben wir den folgenden Code in unserer Form1.cs. Hier rufen wir OnPersonChanged auf, das jeden Code aufruft, der den Delegaten abonniert hat.

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}

OK. So würden Sie dies zum Laufen bringen, ohne Ereignisse und nur Delegierte zu verwenden . Wir haben nur einen öffentlichen Delegierten in eine Klasse eingefügt - Sie können ihn statisch oder als Singleton oder was auch immer erstellen. Großartig.

ABER, ABER, ABER wir wollen nicht das tun, was ich gerade oben beschrieben habe. Weil öffentliche Felder aus vielen, vielen Gründen schlecht sind . Welche Möglichkeiten haben wir? Wie John Skeet beschreibt, sind hier unsere Optionen:

  1. Eine öffentliche Delegatenvariable (das haben wir gerade oben gemacht. Tu das nicht. Ich habe dir oben nur gesagt, warum es schlecht ist.)
  2. Fügen Sie den Delegaten in eine Eigenschaft mit einem get / set ein (Problem hierbei ist, dass Abonnenten sich gegenseitig überschreiben können - wir könnten also eine Reihe von Methoden für den Delegaten abonnieren und dann versehentlich sagen PersonChangedDel = null, dass alle anderen Abonnements gelöscht werden Ein weiteres Problem besteht darin, dass die Benutzer, da sie Zugriff auf den Delegaten haben, die Ziele in der Aufrufliste aufrufen können. Wir möchten nicht, dass externe Benutzer Zugriff darauf haben, wann unsere Ereignisse ausgelöst werden.
  3. Eine Delegatvariable mit den Methoden AddXXXHandler und RemoveXXXHandler

Diese dritte Option ist im Wesentlichen das, was uns ein Ereignis bietet. Wenn wir einen EventHandler deklarieren, erhalten wir Zugriff auf einen Delegaten - nicht öffentlich, nicht als Eigenschaft, sondern als Ereignis, das nur Accessors hinzufügt / entfernt.

Mal sehen, wie das gleiche Programm aussieht, aber jetzt ein Ereignis anstelle des öffentlichen Delegaten verwendet (ich habe auch unseren Mediator in einen Singleton geändert):

Beispiel 2: Mit EventHandler anstelle eines öffentlichen Delegaten

Vermittler:

class Mediator
{

    private static readonly Mediator _Instance = new Mediator();

    private Mediator() { }

    public static Mediator GetInstance()
    {
        return _Instance;
    }

    public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.

    public void OnPersonChanged(object sender, Person p)
    {
        var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
        if (personChangedDelegate != null)
        {
            personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
        }
    }
}

Beachten Sie, dass wenn Sie F12 im EventHandler verwenden, angezeigt wird, dass es sich bei der Definition nur um einen generischen Delegierten mit dem zusätzlichen Objekt "Absender" handelt:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

Die Benutzersteuerung:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
    {
        BindData(e.Person);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

Zum Schluss noch der Form1.cs-Code:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
        Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}

Da der EventHandler und EventArgs als Parameter benötigt, habe ich diese Klasse mit nur einer einzigen Eigenschaft erstellt:

class PersonChangedEventArgs
{
    public Person Person { get; set; }
}

Hoffentlich zeigt Ihnen das ein wenig, warum wir Ereignisse haben und wie sie sich von den Delegierten unterscheiden - aber funktional gleich sind.

Trevor
quelle
Obwohl ich die gute Arbeit in diesem Beitrag sehr schätze und das meiste davon gerne gelesen habe, habe ich immer noch das Gefühl, dass ein Problem nicht angesprochen wird - The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events. In der neuesten Version von Mediatorkönnen Sie immer noch aufrufen, OnPersonChangewenn Sie einen Verweis auf den Singleton haben. Vielleicht sollten Sie erwähnen, dass der MediatorAnsatz dieses bestimmte Verhalten nicht verhindert und näher an einem Ereignisbus liegt.
Ivaylo Slavov
6

Sie können Ereignisse auch in Schnittstellendeklarationen verwenden, nicht jedoch für Delegaten.

Paul Hill
quelle
2
@surfen Interface kann Ereignisse enthalten, aber keine Delegaten.
Alexandr Nikitin
1
Was genau meinst du? Sie können Action a { get; set; }innerhalb einer Schnittstelle Definition haben.
Chiel ten Brinke
6

Was für ein großes Missverständnis zwischen Veranstaltungen und Delegierten !!! Ein Delegat gibt einen TYP an (z. B. a classoder interfacedo), während ein Ereignis nur eine Art MITGLIED ist (z. B. Felder, Eigenschaften usw.). Und genau wie jedes andere Mitglied hat auch eine Veranstaltung einen Typ. Im Falle eines Ereignisses muss der Typ des Ereignisses jedoch von einem Delegierten angegeben werden. Beispielsweise können Sie ein Ereignis eines von einer Schnittstelle definierten Typs NICHT deklarieren.

Abschließend können wir folgende Bemerkung machen: Der Typ eines Ereignisses MUSS von einem Delegierten definiert werden . Dies ist die Hauptbeziehung zwischen einem Ereignis und einem Delegierten und wird in Abschnitt II.18 Definieren von Ereignissen der ECMA-335 (CLI) -Partitionen I bis VI beschrieben :

In der typischen Verwendung identifiziert die TypeSpec (falls vorhanden) einen Delegaten, dessen Signatur mit den Argumenten übereinstimmt, die an die Feuermethode des Ereignisses übergeben wurden.

Diese Tatsache bedeutet jedoch NICHT, dass ein Ereignis ein Hintergrunddelegatenfeld verwendet . In Wahrheit kann ein Ereignis ein Hintergrundfeld eines anderen Datenstrukturtyps Ihrer Wahl verwenden. Wenn Sie ein Ereignis explizit in C # implementieren, können Sie frei wählen, wie Sie die Ereignishandler speichern (beachten Sie, dass Ereignishandler Instanzen des Ereignistyps sind , der wiederum zwingend ein Delegatentyp ist - aus der vorherigen Beobachtung ). Sie können diese Ereignishandler (die delegierte Instanzen sind) jedoch in einer Datenstruktur wie einer Listoder einer Dictionaryanderen oder sogar in einem Hintergrunddelegiertenfeld speichern . Vergessen Sie jedoch nicht, dass Sie KEIN Delegatenfeld verwenden müssen.

Miguel Gamboa
quelle
4

Ein Ereignis in .net ist eine bestimmte Kombination aus einer Add-Methode und einer Remove-Methode, die beide einen bestimmten Delegatentyp erwarten. Sowohl C # als auch vb.net können automatisch Code für die Methoden zum Hinzufügen und Entfernen generieren, die einen Delegaten definieren, der die Ereignisabonnements enthält, und den übergebenen Delegaten zu / von diesem Abonnementdelegierten hinzufügen / entfernen. VB.net generiert außerdem automatisch Code (mit der RaiseEvent-Anweisung), um die Abonnementliste genau dann aufzurufen, wenn sie nicht leer ist. Aus irgendeinem Grund generiert C # letzteres nicht.

Beachten Sie, dass es zwar üblich ist, Ereignisabonnements mit einem Multicast-Delegaten zu verwalten, dies jedoch nicht das einzige Mittel ist. Aus öffentlicher Sicht muss ein potenzieller Ereignisabonnent wissen, wie er ein Objekt wissen lässt, dass es Ereignisse empfangen möchte, aber er muss nicht wissen, welchen Mechanismus der Herausgeber zum Auslösen der Ereignisse verwendet. Beachten Sie auch, dass, wer auch immer die Ereignisdatenstruktur in .net definiert hat, anscheinend der Meinung war, dass es ein öffentliches Mittel zum Auslösen geben sollte, weder C # noch vb.net diese Funktion nutzen.

Superkatze
quelle
3

So definieren Sie ein Ereignis auf einfache Weise:

Ereignis ist eine VERWEIS auf einen Delegierten mit zwei Einschränkungen

  1. Kann nicht direkt aufgerufen werden
  2. Werte können nicht direkt zugewiesen werden (z. B. eventObj = delegateMethod)

Über zwei sind die Schwachstellen für die Delegierten und es wird im Ereignis angesprochen. Ein vollständiges Codebeispiel, um den Unterschied zwischen Geigern zu zeigen, finden Sie hier https://dotnetfiddle.net/5iR3fB .

Schalten Sie den Kommentar zwischen Ereignis und Delegat und Client-Code um, der zu delegierende Werte aufruft / zuweist, um den Unterschied zu verstehen

Hier ist der Inline-Code.

 /*
This is working program in Visual Studio.  It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
        Event is an delegate reference with two restrictions for increased protection

            1. Cannot be invoked directly
            2. Cannot assign value to delegate reference directly

Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/

public class RoomTemperatureController
{
    private int _roomTemperature = 25;//Default/Starting room Temperature
    private bool _isAirConditionTurnedOn = false;//Default AC is Off
    private bool _isHeatTurnedOn = false;//Default Heat is Off
    private bool _tempSimulator = false;
    public  delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
    // public  OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 
    public  event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 

    public RoomTemperatureController()
    {
        WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
    }
    private void InternalRoomTemperatuerHandler(int roomTemp)
    {
        System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
    }

    //User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
    public bool TurnRoomTeperatureSimulator
    {
        set
        {
            _tempSimulator = value;
            if (value)
            {
                SimulateRoomTemperature(); //Turn on Simulator              
            }
        }
        get { return _tempSimulator; }
    }
    public void TurnAirCondition(bool val)
    {
        _isAirConditionTurnedOn = val;
        _isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
        System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
        System.Console.WriteLine("Heat :" + _isHeatTurnedOn);

    }
    public void TurnHeat(bool val)
    {
        _isHeatTurnedOn = val;
        _isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
        System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
        System.Console.WriteLine("Heat :" + _isHeatTurnedOn);

    }

    public async void SimulateRoomTemperature()
    {
        while (_tempSimulator)
        {
            if (_isAirConditionTurnedOn)
                _roomTemperature--;//Decrease Room Temperature if AC is turned On
            if (_isHeatTurnedOn)
                _roomTemperature++;//Decrease Room Temperature if AC is turned On
            System.Console.WriteLine("Temperature :" + _roomTemperature);
            if (WhenRoomTemperatureChange != null)
                WhenRoomTemperatureChange(_roomTemperature);
            System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
        }
    }

}

public class MySweetHome
{
    RoomTemperatureController roomController = null;
    public MySweetHome()
    {
        roomController = new RoomTemperatureController();
        roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
        //roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
        //roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
        roomController.SimulateRoomTemperature();
        System.Threading.Thread.Sleep(5000);
        roomController.TurnAirCondition (true);
        roomController.TurnRoomTeperatureSimulator = true;

    }
    public void TurnHeatOrACBasedOnTemp(int temp)
    {
        if (temp >= 30)
            roomController.TurnAirCondition(true);
        if (temp <= 15)
            roomController.TurnHeat(true);

    }
    public static void Main(string []args)
    {
        MySweetHome home = new MySweetHome();
    }


}
Venkatesh Muniyandi
quelle
2

Delegate ist ein typsicherer Funktionszeiger. Event ist eine Implementierung des Publisher-Subscriber-Entwurfsmusters unter Verwendung eines Delegaten.

Weidong Shen
quelle
0

Wenn Sie Intermediate Language aktivieren, wissen Sie, dass der .net-Compiler den Delegaten in eine versiegelte Klasse in IL konvertiert, mit einigen integrierten Funktionen wie invoke, beginInvoke, endInvoke und delegate class, die von einer anderen Klasse geerbt wurden und möglicherweise als "SystemMulticast" bezeichnet werden. Ich denke, Event ist eine untergeordnete Klasse von Delegaten mit einigen zusätzlichen Eigenschaften.

Der Unterschied zwischen Ereignisinstanz und Delegat besteht darin, dass Sie kein Ereignis außerhalb der Deklaration ausführen können. Wenn Sie ein Ereignis in Klasse A deklarieren, können Sie dieses Ereignis nur in Klasse A ausführen. Wenn Sie einen Delegaten in Klasse A deklarieren, können Sie diesen Delegaten überall verwenden. Ich denke, das ist ein Hauptunterschied zwischen ihnen

Shawn L.
quelle