Wzorzec C # zapobiegający dwukrotnemu podłączeniu obsługi zdarzenia [duplikat]
To pytanie ma już odpowiedź tutaj:
Duplikat: Jak upewnić się, że zdarzenie jest subskrybowane tylko raz i czy został już dodany moduł obsługi zdarzenia?
Mam Singletona, który zapewnia jakąś usługę i moje klasy podłączają się do niektórych wydarzeń na nim, czasami klasa jest podłączony dwa razy do zdarzenia, a następnie zostaje wezwany dwa razy. Szukam klasycznego sposobu, by temu zapobiec. jakoś muszę sprawdzić, czy mam już podłączony do tego wydarzenia...
9 answers
Jawnie zaimplementuj Zdarzenie i sprawdź listę wywołań. Musisz również sprawdzić, czy nie ma null:
using System.Linq; // Required for the .Contains call below:
...
private EventHandler foo;
public event EventHandler Foo
{
add
{
if (foo == null || !foo.GetInvocationList().Contains(value))
{
foo += value;
}
}
remove
{
foo -= value;
}
}
Używając powyższego kodu, jeśli wywołujący subskrybuje Zdarzenie wiele razy, zostanie ono po prostu zignorowane.
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
2011-11-11 21:31:23
Może najpierw usuniesz Zdarzenie za pomocą -=
, jeśli nie zostanie znalezione, wyjątek nie zostanie wyrzucony
/// -= Removes the event if it has been already added, this prevents multiple firing of the event
((System.Windows.Forms.WebBrowser)sender).Document.Click -= new System.Windows.Forms.HtmlElementEventHandler(testii);
((System.Windows.Forms.WebBrowser)sender).Document.Click += new System.Windows.Forms.HtmlElementEventHandler(testii);
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
2011-02-21 22:18:49
Przetestowałem każde rozwiązanie i najlepsze (biorąc pod uwagę wydajność) jest:
private EventHandler _foo;
public event EventHandler Foo {
add {
_foo -= value;
_foo += value;
}
remove {
_foo -= value;
}
}
Nie wymaga użycia Linq. Nie ma potrzeby sprawdzania wartości null przed anulowaniem subskrypcji(szczegóły w MS EventHandler). Nie musisz pamiętać, aby wypisać się wszędzie.
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
2013-06-20 20:15:55
Naprawdę powinieneś się tym zająć na poziomie zlewu, a nie na poziomie źródła. Oznacza to, że nie przepisuj logiki obsługi zdarzeń w źródle zdarzenia-zostaw to samym programom obsługi (zlewom).
Jako twórca serwisu, kim jesteś, żeby twierdzić, że zlewozmywaki można zarejestrować tylko raz? A jeśli z jakiegoś powodu chcą zarejestrować się dwa razy? A jeśli próbujesz poprawić błędy w zlewozmywakach poprzez modyfikację źródła, jest to kolejny dobry powód, aby poprawić te problemy w / align = "left" /
Jestem pewien, że masz swoje powody; źródło zdarzeń, dla których duplikaty są nielegalne, nie jest niezgłębione. Ale być może powinieneś rozważyć alternatywną architekturę, która pozostawia semantykę zdarzenia nienaruszoną.
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
2015-08-11 20:31:56
Musisz zaimplementować dodawanie i usuwanie accesorów w zdarzeniu, a następnie sprawdzić listę docelową delegata lub zapisać cele na liście.
W metodzie add możesz użyć delegata .GetInvocationList metoda uzyskiwania listy celów już dodanych do delegata.
Ponieważ delegaty są zdefiniowane jako porównaj equal, jeśli są połączone z tą samą metodą na tym samym obiekcie docelowym, prawdopodobnie możesz uruchomić tę listę i porównać, a jeśli znajdziesz żaden, który nie jest równy, dodajesz nowy.
Oto przykładowy kod, skompilowany jako aplikacja konsolowa:
using System;
using System.Linq;
namespace DemoApp
{
public class TestClass
{
private EventHandler _Test;
public event EventHandler Test
{
add
{
if (_Test == null || !_Test.GetInvocationList().Contains(value))
_Test += value;
}
remove
{
_Test -= value;
}
}
public void OnTest()
{
if (_Test != null)
_Test(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
TestClass tc = new TestClass();
tc.Test += tc_Test;
tc.Test += tc_Test;
tc.OnTest();
Console.In.ReadLine();
}
static void tc_Test(object sender, EventArgs e)
{
Console.Out.WriteLine("tc_Test called");
}
}
}
Wyjście:
tc_Test called
(tj. tylko raz)
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
2009-06-01 23:00:44
Reactive Extensions (RX) Framework
Microsoftu może być również używany do "subskrybowania tylko raz".
Biorąc pod uwagę Zdarzenie myszy foo.Kliknij, oto jak subskrybować i otrzymywać tylko jedno zaproszenie:
Observable.FromEvent<MouseEventArgs>(foo, "Clicked")
.Take(1)
.Subscribe(MyHandler);
...
private void MyHandler(IEvent<MouseEventArgs> eventInfo)
{
// This will be called just once!
var sender = eventInfo.Sender;
var args = eventInfo.EventArgs;
}
Oprócz funkcji "Subskrybuj raz", podejście RX oferuje możliwość komponowania zdarzeń razem lub filtrowania zdarzeń. Jest całkiem sprytny.
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-08-13 14:28:01
Tworzy akcję zamiast zdarzenia. Twoja klasa może wyglądać tak:
public class MyClass
{
// sender arguments <----- Use this action instead of an event
public Action<object, EventArgs> OnSomeEventOccured;
public void SomeMethod()
{
if(OnSomeEventOccured!=null)
OnSomeEventOccured(this, null);
}
}
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
2013-06-19 14:35:47
Niech twój obiekt singleton sprawdzi listę osób, o których powiadamia i wywoła tylko raz, jeśli zostanie zduplikowany. Ewentualnie, jeśli to możliwe, Odrzuć żądanie załączenia zdarzenia.
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
2009-06-01 22:56:48
W silverlight musisz powiedzieć e. handed = true; w kodzie zdarzenia.
void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true; //this fixes the double event fire problem.
string name = (e.OriginalSource as Image).Tag.ToString();
DoSomething(name);
}
Proszę mnie zaznaczyć, jeśli to pomoże.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
2012-08-23 18:24:10