Akcja vs delegat event

Widziałem deweloperów używających poniższych kodów całkiem alternatywnie. Jaka jest dokładna różnica między nimi, a które z nich są zgodne ze standardem? Są takie same, jak Action i {[3] } jest również delegatem:

public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}

VS

public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}
Author: Bhaskar, 2010-02-17

8 answers

Fwiw, żaden z przykładów nie używa standardowych konwencji. NET. RodzajnikEventHandler<T> powinien zadeklarować Zdarzenie:

public event EventHandler<EmployeeEventArgs> Leave;

Przedrostek " On " powinien być zarezerwowany dla metody chronionej, która wywołuje zdarzenie:

protected virtual void OnLeave(EmployeeEventArgs e) {
    var handler = Leave;
    if (handler != null) handler(this, e);
}

Nie masz , aby zrobić to w ten sposób, ale każdy natychmiast rozpozna wzór, zrozumie Twój kod i wie, jak go używać i dostosowywać.

I ma wielką zaletę, że nie jest zmuszony do wyboru pomiędzy deklaracją niestandardowego delegata i Action<>, To najlepszy sposób. Co odpowiada na twoje pytanie.

 56
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-05 09:01:51

Następujące dwie linijki kodu są prawie równoważne:

public event Action<EmployeeEventAgs> Leave;

W porównaniu do:

public event EventHandler<EmployeeEventAgs> Leave;

Różnica polega na podpisie metody obsługi zdarzenia. Jeśli użyjesz pierwszego podejścia z akcją, możesz mieć:

public void LeaveHandler(EmployeeEventAgs e) { ... }

A potem to:

obj.Leave += LeaveHandler;

Przy drugim podejściu podpis LeaveHandler musi być inny:

public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }

Jest to bardzo ważne , aby zauważyć, że w obu przypadkach słowo kluczowe event jest używane do zadeklaruj członka wydarzenia. Członek zdarzenia zadeklarowany w ten sposób nie jest po prostu polem klasy, mimo że wygląda tak, jakby nim był. Zamiast tego kompilator tworzy ją jako właściwość zdarzenia 1. Właściwości zdarzenia są podobne do zwykłych właściwości, z tym wyjątkiem, że nie mają dostępu get ani set. Kompilator pozwala na ich użycie tylko po lewej stronie przydziałów += i -= (dodawanie lub usuwanie obsługi zdarzenia). Nie ma sposobu, aby nadpisać już przypisane procedury obsługi zdarzeń, lub wywołują Zdarzenie poza klasą deklarującą.

Jeśli w obu przykładach brakowało słowa kluczowego event, można wykonać następujące operacje bez błędu lub ostrzeżenia:

obj.Leave = LeaveHandler;

Który usunie wszystkie zarejestrowane programy obsługi i zastąpi je LeaveHandler.

Dodatkowo, możesz również wykonać to wywołanie:

obj.Leave(new EmployeeEventAgs());

Dwie powyższe sytuacje są uważane za anty-wzorzec , jeśli zamierzasz aby utworzyć wydarzenie. Zdarzenie powinno być wywoływane tylko przez obiekt właściciela i nie powinno pozwalać na niewykrywalne usunięcie subskrybentów. Słowo kluczowe event jest konstrukcją programistyczną. NET, która pomaga trzymać się prawidłowego użycia zdarzeń.

Mając powyższe na uwadze, wierzę, że wiele osób trzyma się podejścia EventHandler, ponieważ jest bardziej mało prawdopodobne, aby użyć EventHandler bez słowa kluczowego event. Działania mają szerszy zakres zastosowania, nie wyglądają tak naturalnie, gdy używane jako wydarzenia. Ta ostatnia jest oczywiście osobistą opinią, ponieważ podejście do obsługi zdarzeń stało się prawdopodobnie zbyt sztywne w moich własnych praktykach kodowania. Mimo to, jeśli działania są właściwie wykorzystywane, nie jest przestępstwem ich wykorzystanie do wydarzeń.


1 właściwość event jest tym, co kompilator automatycznie generuje, gdy widzi kod w ten sposób:

event EventHandler SomeEvent 

Staje się mniej więcej tym samym kodem, co następujący:

private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
    add { _someEvent += value; }
    remove { _someEvent -= value; }
}

Wywołania zdarzeń, które zapisujemy jako to:

this.SomeEvent(sender, args);

Są zamieniane na to:

this._someEvent(sender, args);
 31
Author: Ivaylo Slavov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-04 06:57:14

Action<T> jest dokładnie taki sam jak delegate void ... (T t)

Func<T> jest dokładnie taki sam jak delegate T ... ()

 25
Author: pdr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-15 18:54:46

Action jest tylko skrótem do pełnej deklaracji delegata.

public delegate void Action<T>(T obj)

Http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

Który z nich będzie używany zależy od standardów/stylu kodowania Twojej organizacji.

 7
Author: Darryl Braaten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-15 18:54:09

Tak, Action i Func są po prostu wygodnymi delegatami zdefiniowanymi w clr 3.5.

Action, Func i Lambda to tylko cukier składniowy i wygoda w używaniu delegatów.

Nie ma w nich nic magicznego. Kilka osób napisało proste biblioteki dodatków 2.0, aby dodać tę funkcjonalność do kodu 2.0.

 4
Author: Sky Sanders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 16:41:03

Możesz zajrzeć tutaj, najlepszym opisem jest sprawdzenie, co kompilator faktycznie generuje dla akcji. Nie ma różnicy funkcjonalnej w tym co napisałeś, tylko krótsza, wygodniejsza składnia.

 4
Author: Nick Craver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:32:32

Ogólnie są równoważne. Jednak w kontekście użycia delegata dla typu zdarzenia, konwencją jest użycie EventHandler (gdzie T dziedziczy EventArgs):

public event EventHandler<EmployeeEventArgs> Left;

public void Leave()
{
    OnLeft(this.ID);
}

protected virtual void OnLeft(int id)
{
    if (Left != null) {
        Left(new EmployeeEventArgs(id));
    }
}
 3
Author: Rafa Castaneda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 17:09:38

Mogłeś sam napisać te akcje i Func generic, ale ponieważ są one ogólnie użyteczne, napisali je za Ciebie i umieścili w bibliotekach. Net.

 0
Author: Jason Kleban,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-17 18:57:42