Jakie są różnice między delegatami a wydarzeniami?


317

Jakie są różnice między delegatami a wydarzeniem? Czy oba zawierają odniesienia do funkcji, które można wykonać?



2
to wyjaśnia na przykładzie spójrz unitygeek.com/delegates-events-unity
Rahul Lalit

Odpowiedzi:


283

Event deklaracja dodatkowa warstwa abstrakcji i ochrony na delegata instancji. Ta ochrona zapobiega resetowaniu klientów delegata i jego listy wywołań przez klientów delegata i umożliwia jedynie dodawanie lub usuwanie celów z listy wywołań.


44
Jeśli oczywiście, ta warstwa ochronna również uniemożliwia „klientom” (kod spoza definiującej klasy / struktury) wywoływanie delegata i uzyskanie w jakikolwiek sposób obiektu delegowanego „za” zdarzeniem.
Jeppe Stig Nielsen

7
Nie do końca prawda. Możesz zadeklarować zdarzenie bez instancji delegowania zaplecza. W języku c # można jawnie zaimplementować zdarzenie i użyć innej wybranej struktury danych zaplecza.
Miguel Gamboa

3
@mmcdole, czy możesz podać przykład jego wyjaśnienia?
vivek nuna

103

Aby zrozumieć różnice, spójrz na 2 przykłady

Przykład z delegatami (w tym przypadku akcja - to rodzaj delegata, który nie zwraca wartości)

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

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

Aby użyć delegata, powinieneś zrobić coś takiego:

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

Ten kod działa dobrze, ale możesz mieć słabe punkty.

Na przykład, jeśli napiszę to:

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

z ostatnim wierszem kodu zastąpiłem poprzednie zachowania tylko jednym brakującym +(użyłem =zamiast +=)

Innym słabym punktem jest to, że każda klasa, która korzysta z twojej Animalklasy, może podbić RaiseEventtylko ją sprawdzając animal.RaiseEvent().

Aby uniknąć tych słabych punktów, możesz użyć eventsw c #.

Twoja klasa zwierząt zmieni się w ten sposób:

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"));
    }
}

wywoływać wydarzenia

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

Różnice:

  1. Nie używasz własności publicznej, ale pola publicznego (używając zdarzeń, kompilator chroni twoje pola przed niepożądanym dostępem)
  2. Wydarzenia nie mogą być przypisywane bezpośrednio. W takim przypadku nie spowoduje to pojawienia się poprzedniego błędu, który pokazałem przy nadpisywaniu zachowania.
  3. Nikt spoza twojej klasy nie może podnieść tego wydarzenia.
  4. Zdarzenia mogą być zawarte w deklaracji interfejsu, podczas gdy pole nie

Uwagi:

EventHandler jest zadeklarowany jako następujący delegat:

public delegate void EventHandler (object sender, EventArgs e)

bierze nadawcę (typu Object) i argumenty zdarzenia. Nadawca ma wartość zerową, jeśli pochodzi z metod statycznych.

Ten przykład, który wykorzystuje EventHandler<ArgsSpecial>, można również napisać za pomocą EventHandler.

Patrz tutaj dla dokumentacji o EventHandler


7
Wszystko wyglądało świetnie, dopóki nie natknąłem się na: „Nikt spoza twojej klasy nie jest w stanie podnieść tego wydarzenia”. Co to znaczy? Czy nikt nie może wywoływać, RaiseEventdopóki metoda wywołująca ma dostęp do wystąpienia animalw kodzie używającym zdarzenia?
dance2die

11
@Sung Wydarzenia mogą powstać tylko wewnątrz klasy, być może nie wyjaśniłem tego jasno. W przypadku zdarzeń można wywołać funkcję wywołującą zdarzenie (enkapsulację), ale można ją wywołać tylko z klasy definiującej ją. Daj mi znać, jeśli nie będę jasne.
faby

1
„Nie można bezpośrednio przypisać wydarzeń”. Jeśli nie zrozumiem cię źle, to nie jest prawda. Oto przykład: gist.github.com/Chiel92/36bb3a2d2ac7dd511b96
Chiel ten Brinke

2
@faby, masz na myśli, że chociaż wydarzenie zostało ogłoszone jako publiczne, nadal nie mogę tego zrobić animal.Run(this, new ArgsSpecial("Run faster");?
Pap.

1
@ChieltenBrinke Oczywiście zdarzenie może być przypisane w obrębie członków klasy ... ale nie inaczej.
Jim Balter

94

Oprócz właściwości składniowych i operacyjnych istnieje również różnica semantyczna.

Delegaci są koncepcyjnie szablonami funkcji; oznacza to, że wyrażają umowę, do której musi się stosować funkcja, aby można było uznać ją za „typ” delegata.

Wydarzenia reprezentują ... cóż, wydarzenia. Mają na celu ostrzec kogoś, gdy coś się wydarzy i tak, przestrzegają definicji delegata, ale to nie to samo.

Nawet jeśli byłyby dokładnie takie same (składniowe i w kodzie IL), nadal pozostanie różnica semantyczna. Ogólnie wolę mieć dwie różne nazwy dla dwóch różnych pojęć, nawet jeśli są one implementowane w ten sam sposób (co nie znaczy, że lubię mieć ten sam kod dwa razy).


8
Doskonały opis delegatów.
Sampson

1
Czy możemy więc powiedzieć, że wydarzenie to „specjalny” typ delegata?
Pap.

Nie rozumiem, o co ci chodzi. Możesz użyć delegata, aby „ostrzec kogoś, gdy coś się stanie”. Może byś tego nie zrobił, ale możesz i dlatego nie jest to nieodłączna właściwość zdarzenia.
steve

@Jorge Córdoba przykład delegata i wydarzenia delegat jest właścicielem gazety i wydarzeń (Subskrybuj lub anuluj subskrypcję), a niektórzy ludzie kupują gazetę, a niektórzy nie kupują gazety, co oznacza, że ​​właściciel gazety nie może zmusić każdej osoby do zakupu gazety prawda czy fałsz?
Rahul_Patil

37

Oto kolejny dobry link do odniesienia. http://csharpindepth.com/Articles/Chapter2/Events.aspx

W skrócie, odejmij od artykułu - Wydarzenia są enkapsulacją nad delegatami.

Cytat z artykułu:

Załóżmy, że zdarzenia nie istniały jako koncepcja w języku C # / .NET. W jaki sposób inna klasa zasubskrybuje wydarzenie? Trzy opcje:

  1. Zmienna delegata publicznego

  2. Zmienna delegowana wspierana przez właściwość

  3. Zmienna delegowana za pomocą metod AddXXXHandler i RemoveXXXHandler

Opcja 1 jest wyraźnie okropna, ze wszystkich normalnych powodów, których nie znosimy zmiennych publicznych.

Opcja 2 jest nieco lepsza, ale umożliwia subskrybentom skuteczne wzajemne zastępowanie - byłoby zbyt łatwo napisać someInstance.MyEvent = eventHandler; które zastąpiłyby istniejące programy obsługi zdarzeń zamiast dodawać nowe. Ponadto nadal musisz napisać właściwości.

Opcja 3 jest w zasadzie tym, co dają ci wydarzenia, ale z gwarantowaną konwencją (generowaną przez kompilator i wspieraną przez dodatkowe flagi w IL) i „darmową” implementacją, jeśli jesteś zadowolony z semantyki, którą dają ci zdarzenia podobne do pól. Subskrybowanie i wypisywanie się z wydarzeń jest hermetyzowane bez umożliwienia arbitralnego dostępu do listy procedur obsługi zdarzeń, a języki mogą uprościć sprawę, zapewniając składnię zarówno deklaracji, jak i subskrypcji.


Ładne i zwięzłe wyjaśnienie. Dzięki
Pap

Jest to bardziej kwestia teoretyczna niż cokolwiek innego, ale FWIW zawsze czułem, że argument „Opcja 1 jest zła, ponieważ nie lubimy zmiennych publicznych” może nieco bardziej wyjaśnić. Jeśli on mówi, że ponieważ jest to „złe praktyki OOP”, techniczniepublic Delegate zmienna będzie wystawienie „dane”, ale do mojej najlepszej OOP wiedzy nigdy wspomniane koncepcje zupełnie jak Delegate(jest to ani „obiektem”, ani „komunikat”) , a .NET tak naprawdę ledwo traktuje delegatów jak dane.
jrh

Chociaż chciałbym również udzielić bardziej praktycznych porad, jeśli jesteś w sytuacji, w której chciałbyś upewnić się, że jest tylko jeden moduł obsługi, dobrym rozwiązaniem może być tworzenie własnych AddXXXHandlermetod za pomocą private Delegatezmiennej. W takim przypadku możesz sprawdzić, czy moduł obsługi jest już ustawiony i odpowiednio zareagować. Może to być również dobre ustawienie, jeśli potrzebujesz obiektu trzymającego, Delegateaby móc wyczyścić wszystkie programy obsługi ( eventnie daje ci to żadnej możliwości).
jrh

7

UWAGA: Jeśli masz dostęp do wersji C # 5.0 Unleashed , przeczytaj „Ograniczenia w zwykłym korzystaniu z usług delegatów” w rozdziale 18, zatytułowanym „Wydarzenia”, aby lepiej zrozumieć różnice między nimi.


Zawsze pomaga mi mieć prosty, konkretny przykład. Oto jeden dla społeczności. Najpierw pokażę, w jaki sposób możesz wykorzystać delegatów samodzielnie, aby zrobić to, co dla nas robią Wydarzenia. Następnie pokazuję, jak to samo rozwiązanie działałoby z instancją EventHandler. A potem wyjaśniam, dlaczego NIE chcemy robić tego, co wyjaśnię w pierwszym przykładzie. Ten post został zainspirowany artykułem Johna Skeeta.

Przykład 1: Korzystanie z publicznego delegata

Załóżmy, że mam aplikację WinForms z jednym rozwijanym polem. Lista rozwijana jest powiązana z List<Person>. Gdzie osoba ma właściwości Id, Name, NickName, HairColor. W formularzu głównym znajduje się niestandardowy element sterujący użytkownika, który pokazuje właściwości tej osoby. Gdy ktoś wybierze osobę z listy rozwijanej, etykiety w aktualizacji kontroli użytkownika pokazują właściwości wybranej osoby.

wprowadź opis zdjęcia tutaj

Oto jak to działa. Mamy trzy pliki, które pomagają nam to połączyć:

  • Mediator.cs - klasa statyczna przechowuje delegatów
  • Form1.cs - główny formularz
  • DetailView.cs - kontrola użytkownika pokazuje wszystkie szczegóły

Oto odpowiedni kod dla każdej z klas:

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);
        }
    }
}

Oto nasza kontrola użytkownika:

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;

    }
}

Wreszcie mamy następujący kod w naszym Form1.cs. Tutaj nazywamy się OnPersonChanged, który wywołuje dowolny kod subskrybowany uczestnikowi.

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. W ten sposób działałoby to bez użycia wydarzeń i po prostu przy użyciu delegatów . Po prostu umieszczamy delegata publicznego na zajęciach - możesz ustawić go jako statyczny, singleton, czy cokolwiek innego. Świetny.

ALE, ALE, ALE, nie chcemy robić tego, co właśnie opisałem powyżej. Ponieważ pola publiczne są złe z wielu, wielu powodów. Jakie są nasze opcje? Jak opisuje John Skeet, oto nasze opcje:

  1. Publiczna zmienna delegata (właśnie to zrobiliśmy powyżej. Nie rób tego. Właśnie powiedziałem powyżej, dlaczego jest źle)
  2. Umieść delegata we właściwości za pomocą komendy get / set (problem polega na tym, że subskrybenci mogą się wzajemnie nadpisywać - więc możemy subskrybować kilka metod delegata, a następnie możemy przypadkowo powiedzieć PersonChangedDel = null, usuwając wszystkie pozostałe subskrypcje. innym problemem, który pozostaje tutaj, jest to, że ponieważ użytkownicy mają dostęp do delegata, mogą wywoływać cele na liście wywołań - nie chcemy, aby użytkownicy zewnętrzni mieli dostęp do momentu, w którym zgłaszają nasze zdarzenia.
  3. Zmienna delegowana za pomocą metod AddXXXHandler i RemoveXXXHandler

Ta trzecia opcja jest zasadniczo tym, co daje nam wydarzenie. Kiedy deklarujemy EventHandler, daje nam dostęp do delegata - nie publicznie, nie jako właściwość, ale jako to, co nazywamy zdarzeniem, które właśnie dodało / usunęło akcesory.

Zobaczmy, jak wygląda ten sam program, ale teraz używam Eventu zamiast publicznego delegata (zmieniłem również naszego Mediatora na singleton):

Przykład 2: Z EventHandler zamiast z publicznego delegata

Mediator:

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 });
        }
    }
}

Zauważ, że jeśli użyjesz klawisza F12 w EventHandler, pokaże ci, że definicja jest tylko ogólnym delegatem z dodatkowym obiektem „nadawcy”:

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

Kontrola użytkownika:

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;

    }
}

Wreszcie, oto kod Form1.cs:

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

Ponieważ EventHandler chce i EventArgs jako parametr, stworzyłem tę klasę z jedną tylko właściwością:

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

Mam nadzieję, że to trochę pokazuje, dlaczego mamy wydarzenia i jak różnią się one - ale funkcjonalnie takie same - jak delegaci.


Chociaż doceniam całą dobrą pracę w tym poście i lubię czytać większość z nich, nadal uważam, że jeden problem nie został rozwiązany - 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. W najnowszej wersji Mediatornadal możesz dzwonić za OnPersonChangekażdym razem, gdy masz odniesienie do singletonu. Może powinieneś wspomnieć, że takie Mediatorpodejście nie zapobiega temu konkretnemu zachowaniu i jest bliższe magistrali zdarzeń.
Ivaylo Slavov

6

Możesz także używać zdarzeń w deklaracjach interfejsu, a nie w przypadku delegatów.


2
Interfejs @surfen może zawierać zdarzenia, ale nie delegatów.
Alexandr Nikitin

1
Co dokładnie masz na myśli? Możesz mieć Action a { get; set; }wewnątrz definicji interfejsu.
Chiel ten Brinke

6

Co za wielkie nieporozumienie między wydarzeniami a delegatami !!! Delegat określa TYP (na przykład a classlub interfacenie), podczas gdy zdarzenie jest tylko rodzajem CZŁONKA (np. Pola, właściwości itp.). I, jak każdy inny członek, wydarzenie ma również swój typ. Jednak w przypadku zdarzenia typ zdarzenia musi zostać określony przez delegata. Na przykład NIE MOŻNA zadeklarować zdarzenia typu określonego przez interfejs.

Podsumowując, możemy dokonać następującej Obserwacji: rodzaj zdarzenia MUSI być zdefiniowany przez delegata . Jest to główna relacja między wydarzeniem a delegatem i została opisana w sekcji II.18 Definiowanie zdarzeń w partycjach od I do VI ECMA-335 (CLI) :

W typowym użyciu TypeSpec (jeśli jest obecny) identyfikuje delegata, którego podpis odpowiada argumentom przekazanym do metody wywoływania zdarzenia.

Jednak fakt ten NIE oznacza, że ​​zdarzenie korzysta z pola delegowania kopii zapasowej . W rzeczywistości zdarzenie może wykorzystywać pole zaplecza dowolnego innego typu struktury danych, który wybierzesz. Jeśli zaimplementujesz zdarzenie jawnie w języku C #, możesz wybrać sposób przechowywania procedur obsługi zdarzeń (pamiętaj, że procedury obsługi zdarzeń są instancjami typu zdarzenia , które z kolei jest obowiązkowo typem delegata --- z poprzedniej obserwacji ). Można jednak przechowywać te procedury obsługi zdarzeń (które są instancjami delegowanymi) w strukturze danych, takiej jak a Listlub a Dictionarylub w dowolnym innym miejscu, a nawet w polu delegowania kopii zapasowej. Ale nie zapominaj, że NIE jest obowiązkowe korzystanie z pola delegowanego.


4

Zdarzenie w .net to wyznaczona kombinacja metody Add i Remove, które oczekują określonego rodzaju delegata. Zarówno C #, jak i vb.net mogą automatycznie generować kod dla metod dodawania i usuwania, które definiują uczestnika do przechowywania subskrypcji zdarzeń oraz dodawania / usuwania przekazanego w delegagte do / z tego uczestnika subskrypcji. VB.net automatycznie wygeneruje również kod (z instrukcją RaiseEvent), aby wywołać listę subskrypcji tylko wtedy, gdy nie jest pusta; z jakiegoś powodu C # nie generuje tego drugiego.

Należy pamiętać, że chociaż zarządzanie subskrypcjami zdarzeń przy użyciu delegata multiemisji jest powszechne, nie jest to jedyny sposób. Z publicznego punktu widzenia potencjalny subskrybent zdarzenia musi wiedzieć, jak powiadomić obiekt, że chce odbierać zdarzenia, ale nie musi wiedzieć, jakiego mechanizmu użyje wydawca, aby wywołać zdarzenia. Zauważ też, że chociaż ktokolwiek zdefiniował strukturę danych zdarzenia w .net najwyraźniej myślał, że powinien istnieć publiczny sposób ich podniesienia, ani C #, ani vb.net nie korzystają z tej funkcji.


3

Aby w prosty sposób zdefiniować zdarzenie:

Wydarzenie jest ODNIESIENIEM do delegata z dwoma ograniczeniami

  1. Nie można wywoływać bezpośrednio
  2. Nie można przypisać wartości bezpośrednio (np. EventObj = delegateMethod)

Powyżej dwóch są słabe punkty dla delegatów i jest to uwzględnione w przypadku. Kompletny przykładowy kod, aby pokazać różnicę w skrzypku jest tutaj https://dotnetfiddle.net/5iR3fB .

Przełącz komentarz między Zdarzeniem a Delegatem i kodem klienta, który wywołuje / przypisuje wartości do delegowania, aby zrozumieć różnicę

Oto kod wewnętrzny.

 /*
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();
    }


}

2

Delegat jest wskaźnikiem funkcji bezpiecznym dla typu. Event jest implementacją wzorca projektowego wydawca-subskrybent przy użyciu delegata.


0

Jeśli zaznaczysz język średniozaawansowany, będziesz wiedział, że kompilator .net konwertuje delegata na zapieczętowaną klasę w IL z niektórymi funkcjami wbudowanymi, takimi jak invoke, beginInvoke, endInvoke i klasa delegowana odziedziczona z innej klasy, być może nazywanej „SystemMulticast”. Wydaje mi się, że Event jest klasą potomną Delegata z pewnymi dodatkowymi właściwościami.

Różnica między instancją zdarzenia a delegatem polega na tym, że nie można uruchomić zdarzenia poza deklaracją. Jeśli zadeklarujesz zdarzenie w klasie A, możesz je uruchomić tylko w klasie A. Jeśli zadeklarujesz uczestnika w klasie A, możesz go użyć w dowolnym miejscu. Myślę, że to główna różnica między nimi

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.