2008-10-29 6 views
59

Zło czy nie zło?Czy wywołanie metody rozszerzenia na odwołaniu "zerowym" (np. Zdarzenie bez subskrybentów) jest złe?

public static void Raise(this EventHandler handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     handler(sender, args); 
    } 
} 

// Usage: 
MyButtonClicked.Raise(this, EventArgs.Empty); 

// This works too! Evil? 
EventHandler handler = null; 
handler.Raise(this, EVentArgs.Empty); 

Należy pamiętać, że ze względu na charakter metod rozszerzających, MyButtonClicked.Raise nie rzuci NullReferenceException jeśli MyButtonClicked jest null. (Np. Nie ma słuchaczy zdarzenia MyButtonClicked).

Zło czy nie?

+0

Lepsze pytanie: przydatne czy nie? –

+8

Jest to przydatne. Zamiast zaśmiecać setki "if (SomeEvent! = Null) SomeEvent (this, args)" wokół naszej bazy kodu, możemy zastąpić ją pojedynczą linią. –

+0

Możesz też utworzyć "manekina obsługi" dla swojego wydarzenia, aby upewnić się, że nigdy nie jest pusta. –

Odpowiedz

35

Nie zło. Szkoda, że ​​wydarzenia nie działały w ten sposób domyślnie. Czy ktoś może wyjaśnić, dlaczego wydarzenie bez subskrybentów ma wartość zerową?

+2

Zgadzam się, że wydarzenia bez subskrybentów nie powinny być puste. Wydaje się raczej głupotą, że wydarzenie bez subskrybentów ma wartość null - z pewnością mogliby zainicjować to z pewną klasą wielokrotnego użytku z pustą listą subskrypcji. Niestety, jest już za późno na zmiany. –

+0

Całkowicie się zgadzam i mam przeciążenie, które domyślnie argumentuje args do EventArgs.Empty. –

+1

Posiadanie zdarzeń bez subskrybentów jest zerowe. To, co jest zepsute, polega na tym, że próba wywołania zdarzenia o wartości pustej, która ma typ void return, powoduje wyjątek. Wywołanie delegata zerowego powinno spowodować wyjątek, ale pole oznaczone jako * zdarzenie * nie powinno być w takim przypadku traktowane jako delegat. – supercat

5

Dlaczego to byłoby złe?

Jego cel jest jasny: Podnosi zdarzenie MyButtonClicked.

Dodaje narzut funkcji, ale w .NET albo zostanie zoptymalizowany, albo całkiem szybki.

To jest trochę trywialne, ale rozwiązuje moją największą skargę za pomocą C#.

Podsumowując, uważam, że to fantastyczny pomysł i prawdopodobnie go ukradnie.

+0

To byłoby złe tylko dlatego, że nie wyrzuci wyjątku, jeśli MyButtonClick ma wartość null. Na przykład. jest to poprawne: EventHandler click = null; click.Raise (...); –

+1

+1 za kradzież dobrych pomysłów. –

+0

Nie można ustawić wartości null EventHandler. Jedynym sposobem, w jaki może być zerowy, jest to, że nikt nie słucha wydarzenia i nie sądzę, że zgłaszanie zdarzeń, których nikt nie słucha, jest zdarzeniem wyjątkowym. – David

14

Zawsze można zadeklarować zdarzeń jak to (nie, że ja go polecam):

public event EventHandler<EventArgs> OnClicked = delegate { }; 

ten sposób mają coś przypisaną do nich, kiedy je połączyć, żeby nie rzucać wyjątku null pointer .

Prawdopodobnie można pozbyć się hasła delegata w C# 3.0 ...

+0

Polecam. Jest zgodny z zasadami dobrego obywatelstwa. –

+0

Czy przeczytałeś to również w C# In Jena Skeeta? :) – dahvyd

0

Nie powiedziałbym, że to złe, ale jestem zainteresowany w jaki sposób metoda rozszerzenie pasuje do

protected virtual OnSomeEvent(EventArgs e){ } 

wzór i sposób, w jaki obsługuje on rozszerzalność poprzez dziedziczenie. Czy zakłada, że ​​wszystkie podklasy będą obsługiwać zdarzenie zamiast przesłonić metodę?

+0

Nie powinno to wpłynąć na to.Wewnątrz OnSomeEvent używałbyś metody rozszerzenia zamiast zwykłego "czeku na null, raise if not null". –

6

Pochodzenie z tła Java zawsze wydawało mi się dziwne. Myślę, że nikt nie słuchający wydarzenia jest całkowicie poprawny. Zwłaszcza, gdy słuchacze są dodawane i usuwane dynamicznie.

Dla mnie jest to jeden z gottch C#, który powoduje błędy, gdy ludzie nie wiedzą/zapominają sprawdzić za każdym razem wartość zerową.

Ukrywanie tego szczegółu implementacji wydaje się dobrym planem, ponieważ nie pomaga w czytelności sprawdzania wartości zerowych za każdym razem. Jestem pewien, że MSFT powiedzą, że jest wzrost wydajności w nie konstytuowaniu zdarzenia, jeśli nikt nie słucha, ale imho jest on znacznie przeważany przez bezsensowny wskaźnik zerowy wyjątków/zmniejszenie czytelności w większości kodów biznesowych.

Chciałbym również dodać te dwie metody do klasy:

public static void Raise(this EventHandler handler, object sender) 
    { 
     Raise(handler, sender, EventArgs.Empty); 
    } 

    public static void Raise<TA>(this EventHandler<TA> handler, object sender, TA args) 
     where TA : EventArgs 
    { 
     if (handler != null) 
     { 
      handler(sender, args); 
     } 
    } 
0

Chociaż nie describ go jako złego, to nadal ma negatywny wpływu, jak dodaje niepotrzebny narzut:

dzwoniąc

myEvent.Raise(this, new EventArgs());

się EventArgs obiekt jest zainicjowany w każdej sytuacji, nawet jeśli nikt subskrybowanych myEvent.

Podczas korzystania

if (myEvent!= null) { 
    myEvent(this, new EventArgs()); 
} 

EventArgs jest inicjowana tylko jeśli ktoś subskrybuje myEvent.

+2

Tak, prawda. Jestem skłonny zamienić trochę alokacji pamięci na bardziej czytelny, solidny kod. –

+2

Obciążenie jest minimalne i jeśli spojrzysz na to, jak wykonane są wszystkie podstawowe pliki, implementują następujący wzór: public void SomeMethod() { OnSomeEvent (new SomeEventArgs()); } chroniony wirtualnego nieważne OnSomeEvent (SomeEventArgs e) {if (SomeEvent! = Null) { SomeEvent (ta, E); } } – Bronumski

+3

Użyj EventArgs.Empty zamiast –

-2

Wyrzucenie wyjątku, gdy nie ma obsługi, nie jest najbardziej pożądane. Jeśli nie ma instrukcji obsługi, lepiej być pustym niż zerowym.

+0

To naprawdę nie dodaje nic do wątku. -1 –

+0

@MattEllen Ups, myślałem, że pomoże to w poznaniu ogólnej praktyki. Biorąc pod uwagę komfort programisty. Dzięki i tak – Prakash

Powiązane problemy