EventHandler delegate and EventHandler event

0

Cześć.
Robię sobie powtórkę w wolnym czasie i jestem przy eventach a głupio mi pytać się o to w pracy.
Tutaj jest przykład obsługi zdarzenia za pomocą samej delegaty i event delegaty.
Możecie mi wytłumaczyć zatem po co u licha jest event ?

O tak jak tutaj:

using System;
namespace ConsoleApp1
{
    class Car
    {
        //subscribed delegates
        public EventHandler eventHandlerDelegate;
        private int speed;
        public void SpeedMe()
        {
            speed++;
            if (speed > 2)
                if(eventHandlerDelegate != null)
                    eventHandlerDelegate.Invoke(this, new EventArgs());
        }
    }
    class Truck
    {
        //subscribed events
        private int speed;
        public event EventHandler bumEvent;
        public void SpeedMe()
        {
            speed++;
            if (speed > 2)
                bumEvent?.Invoke(this, new EventArgs());
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //delegates
            Car car1 = new Car();          
            car1.eventHandlerDelegate += Bum;

            car1.SpeedMe();
            car1.SpeedMe();
            car1.SpeedMe(); //"bum car 1,2"

            //events
            Truck truck1 = new Truck();
            truck1.bumEvent += new EventHandler(Bum);

            truck1.SpeedMe();
            truck1.SpeedMe();
            truck1.SpeedMe(); //"bum truck 1,2"
        }
        private static void Bum(object o, EventArgs arg) { Console.WriteLine("bum"); }
    }
}
2

Zasadniczo, masz rację, tutaj nie ma olbrzymiej różnicy. Bo event to taki wrapper na delegaty, aby zrobic sobie enkapsulację. Trochę podobna sytuacja jak z polami i właściwościami, tj. pilnuje, abyś się (albo ktoś inny, kto korzysta z twojego kodu) nie ugryzł(a) w tyłek przypadkiem.

Zobacz przykład:

Car car1 = new Car();                      
car1.eventHandlerDelegate += (o, e) => { Console.WriteLine("bum2"); }; // zrobi że będzie bum2
car1.eventHandlerDelegate = Bum; // zrobi, ze będzie również bum zwykłe

car1.SpeedMe();
car1.SpeedMe();
car1.SpeedMe(); //"bum car 1,2"

Robi "bum", a powinno robić "bum2 bum". Widzisz dlaczego?

Bo tam jest =, a nie += w drugim przypisaniu. Było to jasno widoczne za pierwszym razem?

Jeżeli użyjesz po prostu delegata to on jest przypisywalny i można zrobić coś takiego. Eventy ochronią cię właśnie przed takimi błędami w stylu nadpisywania delegatów, zmiany wszystkiego na null czy w ogóle odpalaniu słuchaczy spoza klasy:

Car car1 = new Car();                      
car1.eventHandlerDelegate += Bum;
car1.eventHandlerDelegate.Invoke(null, null);
    // haha, odpaliłem, że zdarzenie odpaliło, a ono nie nastąpiło tak naprawdę!

https://stackoverflow.com/questions/15182802/why-use-events-for-what-i-can-do-with-delegates

0

Dziękuję za wyjaśnienie.
Rozumiem, że idea jest taka, że z poziomu klienta, subskrybenta nie mamy dostępu do listy wywołań delegaty.
Nie możemy jej zepsuć, tudzież odpalić.
Np. tym poleceniem Invoke(null, null) ; wywołałeś wszystkie metody z listy wywołań :) - co dla EVENT'a nie przejdzie.
Z poziomu subskrybenta nie ma żadnych metod pod eventem.

Z poziomu sendera nie ma różnicy event bumEvent vs eventHandlerDelegate
Z poziomu debugera klienta też nie różnicy event bumEvent vs eventHandlerDelegate.
screenshot-20200402214601.png

Wychodzi mi na to że słówko **EVENT **powoduje, to że delegata z poziomu klienta staje się ułomna, ograniczona tj.

  • nie można do niej przypisać =
  • nie można na niej wywołać metody bumEvent.Ivoke(..) czy bumEvent.GetInvocationList().

Ten komunikat własnie o tym mówi
screenshot-20200402214214.png

Jeszcze jedna uwaga tak napisany program po usunięciu EVENT działa tak samo.

Poprawka do mojego kodu z posta linia 43 bez new) po prostu

truck1.bumEvent += Bum;
0

twój program wygląda tak: Teraz będziesz wiedział jaka jest różnica

0
Zimny Krawiec napisał(a):

twój program wygląda tak: Teraz będziesz wiedział jaka jest różnica

Heh dzięki, przeceniasz mnie, nie znam IL, ale pewnie Tobie to coś mówi, jakbyś dodał kilka zdań opisu to chętnie się czegoś dowiem.
Czy chodzi Ci o te różnice :
DELEGAT

public EventHandler eventHandlerDel;	

IL


	.field public class [mscorlib]System.EventHandler eventHandlerDel

EVENT

public event EventHandler eventHandlerEv;

IL

	 .event [mscorlib]System.EventHandler eventHandlerEv
	  {
		.addon instance void ConsoleApp1.Truck::add_eventHandlerEv(class [mscorlib]System.EventHandler)
		.removeon instance void ConsoleApp1.Truck::remove_eventHandlerEv(class [mscorlib]System.EventHandler)
	  } // end of event Truck::eventHandlerEv
	} // end of class ConsoleApp1.Truck
2

event w tym zapisie to po prostu odpowiednik automatycznie wygenerowanego propertisa tyle że dla delegatów:

 public int Speed { get; set };
 public event EventHandler BumEvent;

skrócony zapis można zastąpić pełnym razem z jawnie zdefiniowanym polem, to jest dokładnie to samo co:

private int speed;
private EventHandler bumEvent;

public int Speed
{
    get
    {
        return speed;
    }
    set
    {
        speed = value;
    }
}


public event EventHandler BumEvent
{
    add
    {
        bumEvent += value;
    }
    remove
    {
        bumEvent -= value;
    }
}

czyli widzimy że jedynie co event zmienia to zamiast metod set i get dostajemy dwie metody add i remove, nie ma żadnej magii, ani żadnych dodatkowych typów. Nasz delegat pozostaje prywatny, a upubliczniamy tylko dwie metody umożliwiajace dodawanie i usuwanie na nim.

0

Te metody add i remove wyglądają mniej więcej tak.

using System;

namespace ConsoleApp25
{
    delegate int Dzialanie(int x1, int x2);

    class Program
    {
        private static Dzialanie dz;
        static void Main(string[] args)
        {

            add_dz(new Dzialanie(Dodaj));
            add_dz(new Dzialanie(Dodaj));
            Console.WriteLine(dz(10, 10));

            remove_dz(new Dzialanie(Dodaj));
            Console.WriteLine(dz(10, 10));

            add_dz(new Dzialanie(Odejmij));

            Console.WriteLine(dz(10, 10));

        }

        public static int Dodaj(int x1, int x2)
        {
            return x1 + x2;
        }

        public static int Odejmij(int x1, int x2)
        {
            return x1 - x2;
        }

        public static void add_dz(Dzialanie value)
        {
            Dzialanie loc0, loc1, loc2;
            loc0 = dz;
            do
            {
                loc1 = loc0;
                loc2 = (Dzialanie)System.Delegate.Combine(loc1, value);
                loc0 = System.Threading.Interlocked.CompareExchange<Dzialanie>(ref dz, loc2, loc1);
            } while (!Object.ReferenceEquals(loc0, loc1));

        }

        public static void remove_dz(Dzialanie value)
        {
            Dzialanie loc0, loc1, loc2;
            loc0 = dz;
            do
            {
                loc1 = loc0;
                loc2 = (Dzialanie)System.Delegate.Remove(loc1, value);
                loc0 = System.Threading.Interlocked.CompareExchange<Dzialanie>(ref dz, loc2, loc1);
            } while (!Object.ReferenceEquals(loc0, loc1));

        }

    }
}

using System;

namespace ConsoleApp25
{
    delegate int Dzialanie(int x1, int x2);

    class Program
    {

       public static event Dzialanie dz;
        static void Main(string[] args)
        {

            dz += Dodaj;
            dz += Dodaj;
            Console.WriteLine(dz(10, 10));

            dz -= Dodaj;
            Console.WriteLine(dz(10, 10));

            dz += Odejmij;

            Console.WriteLine(dz(10, 10));

        }

        public static int Dodaj(int x1, int x2)
        {
            return x1 + x2;
        }

        public static int Odejmij(int x1, int x2)
        {
            return x1 - x2;
        }

        

    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1