2010-08-31 11 views
5

Widziałem ludzi, którzy opierali się na przekazywaniu metod wywołania zwrotnego/zdarzeń, a czasami wręczali im lambdy.subskrypcja metody kontra subskrybent lambda - co i dlaczego?

Czy ktokolwiek może mówić o jakiejkolwiek różnicy między tymi dwoma? Początkowo sądziłem, że są takie same, ale niekonsekwencja, którą widziałem, zaimplementowana czasami sprawia, że ​​zastanawiam się, czy jest przypadek, w którym jeden jest lepszy od drugiego? Oczywiście, jeśli jest bardzo duża ilość kodu, to nie powinno to być lambda na miejscu, ale poza tym ..

Czy możesz podać wszystkie różnice między tymi dwoma, jeśli takie istnieją, i objaśnić zasady, których używasz do wyboru między dwa, gdy oba są dostępne?

Odpowiedz

7

Jedną z największych różnic między nimi jest łatwość, z jaką możesz zrezygnować z subskrypcji. W przypadku metody opartej na metodzie rezygnacji z subskrypcji jest to prosta operacja, po prostu użyj oryginalnej metody, po prostu użyj oryginalnej metody, korzystając z oryginalnej metody lambdas, która nie jest tak prosta. należy przechowywać z dala wyrażenia lambda i być wykorzystane później do unsbuscribe z imprezy

m_button.Click += delegate { Console.Write("here"); } 
... 
// Fail 
m_button.Click -= delegate { Console.Write("here"); } 

EventHandler del = delegate { Console.Write("here"); } 
m_button.Click += del; 
... 
m_button.Click -= del; 

To naprawdę nie umniejsza wygody przy użyciu wyrażeń lambda.

+0

Mam nawyk + = (nadawca, e) => {} i nigdy nie myślałem o tym, ale nie mogłem usunąć tego konkretnego słuchacza, jeśli chciałem, dobry punkt .. –

+0

@ Jimmy, często razy nie musisz i ten punkt staje się nieistotny. Ale jest to denerwujące w czasach, kiedy to robisz. – JaredPar

2

W większości języków z lambdami (w tym C#), utworzenie lambda wewnątrz metody tworzy zamknięcie - to znaczy zmienne lokalne w metodzie deklarującej będą widoczne dla lambda. To jest największa różnica, o której wiem.

Oprócz tego, chyba że w jakiś sposób nazwałbyś swój program obsługi zdarzeń, w sposób dostępny w innej funkcji, trudno będzie później odłączyć obsługę zdarzeń. Można to zrobić, przechowując delegata w zmiennej instancji lub na poziomie klasy, ale może to być trochę brzydkie.

1

Największym powodem używania Lambdy jest opóźnione wykonanie, tj. Zdefiniowanie operacji, które chcesz wykonać, ale nie będziesz mieć parametrów do późniejszego czasu. Generalnie nie używa się lambdas dla zdarzeń i wywołań zwrotnych; używasz anonimowych metod.

Stosowanie anonimowych metod dla zdarzeń i wywołań zwrotnych jest proste w przypadku prostych zdarzeń, których nie trzeba anulować. Największym czynnikiem decydującym o mnie jest to, gdzie je deklaruję. Nie będę zadeklarować obsługi zdarzeń dla formularza jako anonimowej metody, ale jeśli mam krótkotrwałą potrzebę połączenia się z wydarzeniem, może to być w porządku.

Ogólnie używam rzeczywistych metod wywołań zwrotnych i zdarzeń bardziej niż metod anonimowych; zdarzenia, które obsługuję, są powiązane z czasem życia obiektu, a nie z czasem trwania metody, i stwierdzam, że wyraźniej w kodzie jest to, że callbacki są jasno zdefiniowane poza funkcją, która je podpina. Niektóre z nich to osobiste preferencje.

+1

Lambda nie jest opóźniona w normalnym znaczeniu tego słowa. Są tylko delegatami i mają normalne zachowanie delegatów. Opóźnione wykonanie jest zwykle używane do opisu zapytań LINQ, które mają inną semantykę niż lambda. – JaredPar

+0

Masz rację, dobra uwaga. LINQ to miejsce, w którym przede wszystkim używam Lambdas, różnica rozmyła się w mojej głowie –

0

W większości przypadków istnieje niewielka różnica praktyczna. To, którego użyć, to głównie kwestia osobistych preferencji (tj. Tego, co chcesz, aby kod wyglądał tak, jak na ). W niektórych przypadkach, istnieje kilka praktycznych powodów, aby preferować jeden nad drugim:

  1. jak zauważono w the accepted answer, wypisywanie metoda anonimowy jest bardziej złożona niż wypisywanie nazwany metody. Bez nazwy nie można odwoływać się do anonimowej metody z wyjątkiem instancji delegata utworzonej w środowisku wykonawczym, w której deklarowana jest metoda anonimowa. Przy użyciu nazwanej metody delegat może zostać zrezygnowany z subskrypcji bez zachowania odniesienia do pierwotnego uczestnika (lub jego odpowiednika).
  2. Z drugiej strony, powodem preferowania wyrażenia lambda jest sytuacja, w której program obsługi zdarzenia jest szczegółem implementacji unikatowym dla podanej metody, w której deklarowana jest metoda lambda/anonimowa. Może to pomóc w utrzymaniu szczegółów implementacji prywatnych i lokalnych w metodzie, w której są używane.
  3. Innym powodem, dla którego można użyć wyrażenia lambda, jest konieczność "dostosowania" typu uczestnika. To znaczy. chcesz wywoływać nazwaną metodę obsługi zdarzenia, ale ta metoda ma inny podpis niż wymagany przez zdarzenie. Może się tak zdarzyć, gdy chcesz ponownie użyć tej metody dla różnych zdarzeń lub innych sytuacji, w których niektóre parametry zdarzenia mogą nie mieć zastosowania. Innym przypadkiem może być sytuacja, w której chcesz wprowadzić nowy parametr o wartości, której nie może dostarczyć wydarzenie (np. Indeks dla zbioru obiektów, które mają to samo wydarzenie, które chcesz zasubskrybować).

Istnieje jeden specjalny przypadek, który może czasami pojawić się, który jest wyborem, czy użyć nazwanej metody samodzielnie, czy też użyć anonimowej metody, która następnie wywołuje tę nazwaną metodę. Ważne jest, aby pamiętać, że w przypadku braku innych praktycznych powodów wyboru jednego z nich, użycie nazwanej metody jest nieznacznie bardziej skuteczne w tym konkretnym przypadku, ponieważ usuwa jedno wywołanie metody z wywołania. W praktyce prawdopodobnie nigdy nie zauważysz różnicy, ale jest to tylko kwestia kosztów ogólnych, więc jeśli nie ma konkretnego, praktycznego powodu do jej poniesienia, prawdopodobnie powinieneś tego unikać, tj. Zasubskrybuj bezpośrednio nazwaną metodę.