2012-02-16 10 views
22

Nie można zmodyfikować EventArgs w procedurach obsługi zdarzeń w celu przekazania informacji do klasy wywołującej zdarzenie?Korzystanie z EventArgs w celu przekazania informacji do wywołania klasy

Na przykład, jeśli mam niskopoziomową klasę komunikacyjną wymagającą sprawdzenia poprawności certyfikatu dla SSL, ale nie ma ona możliwości sprawdzenia, jak wygląda ważny certyfikat, ponieważ jest to wiedza różnych użytkowników tej klasy.

class ValidationEventArgs : System.EventArgs 
{ 
    public X509Certificate Certificate { get; set; } 
    public bool Valid { get; set; } 
} 

Następnie w obiektach wykorzystujących je podłączyć do zdarzenia i sprawdzić go w jakiś sposób zmienia flagę Valid, aby wskazać, czy certyfikat jest dopuszczalne, czy nie.

comms.ValidationEvent += CertValidationHandler; 

void CertValidationHandler(ValidationEventArgs args) 
{ 
    if (args.Certificate.Issuer.Contains(COMPANY_NAME) 
     args.Valid = true; 
} 

znalazłem references z EventArgs jest używany tak, ale widziałem też ludzi, mówiąc, że nie jest to zalecane.

Edytuj: Może powinienem wyjaśnić, że nie chodzi o dziedziczenie EventArgs, ale używanie ich jako dwukierunkowego kanału komunikacji. Jak zauważyli inni, jest to dopuszczalne, a jakikolwiek hałas, jaki Google podejmuje na odwrót, to prawdopodobnie ludzie, którzy źle zrozumieli/niewłaściwie wykorzystali tę koncepcję i teraz mają tę samą osobistą krucjatę przeciwko goto.

+6

Kto mówi, że nie jest to zalecane? Dzieje się tak cały czas w ramach. Spójrz na ['CancelEventArgs'] (http://msdn.microsoft.com/en-us/library/system.componentmodel.canceleventargs.aspx); to nie jest o wiele bardziej podstawowe. –

+0

Googling dookoła Mam wrażenie, że posiadanie zmiennej EventArgs nie jest czymś, co należy zrobić, prawdopodobnie dlatego, że ktoś kiedyś nadużył go w niewłaściwy sposób. Dzięki –

+0

Tak jak może mieć czas i miejsce, w których można z niego korzystać, używanie go w niewłaściwy sposób i miejsce jest złe, ale to nie czyni go złym. – MikeT

Odpowiedz

41

Zadaj sobie następujące pytanie: "kiedy publikuję wydarzenie, czy chcę, aby subskrybent zmienił dowolne wartości EventArgs"? Jeśli odpowiedź brzmi "nie", np. transmitujesz informacje tylko do odczytu, a następnie unieważniasz klasę, jednak jeśli potrzebujesz informacji zwrotnej od subskrybenta, dokonaj zmian właściwości, które wymagają zmiany.

Aby wyjaśnić, w przykładzie emisji chcemy powiedzieć abonentowi coś, ale nie pozwolić im zmienić wartości.

public class ProgressEventArgs : EventArgs 
{ 
    public ProgressEventArgs(int current) 
    { 
     this.Current = current; 
    } 

    public int Current { get; private set; } 
} 

Jednocześnie możemy również podnieść wydarzenie, aby poprosić o informacje, których sama klasa nie zna.

public class FeedbackEventArgs : EventArgs 
{ 
    public bool ShouldContinue { get; set; } 
    public string Reason { get; set; } 
} 
+0

Podobało mi się to, pokazuje właściwe pytania do zadawania sobie pytań. –

+2

Wiem, że to jest stare, ale chciałbym zaznaczyć, że należy zachować ostrożność podczas korzystania z tego podejścia, ponieważ może być więcej niż jeden subskrybent na zdarzenie, ale to byłby ten sam obiekt zdarzenia, który byłby przekazywany, więc używanie prostych ustawień mogło powoduje nadpisanie danych. – Pharap

+0

@Pharap dobry punkt! W zmiennym przykładzie będzie to przypadek "wygranych ostatniego zapisu". –

2

Nie jestem świadomy żadnych zaleceń dotyczących dziedziczenia z EventArgs; O ile wiem, dziedziczenie z niego jest dobrą praktyką.

Zgodnie z ogólną zasadą sugeruję, aby uczynić swoje klasy pochodne niezmienne. To sprawi, że przejście między wątkami będzie o wiele bezpieczniejsze, jeśli musisz to zrobić. Najprostszym sposobem, aby to zrobić, jest zadeklarowanie swoich właściwości jako { get; private set; } i ustawienie ich tylko w konstruktorze. Oczywiście nie możesz tego zrobić w konkretnym przypadku użycia w pytaniu, ale powinieneś zrobić to w miarę możliwości.

+0

+1 - uzgodniono. Używano tej metody mnóstwo razy. – ChrisBD

+0

Tak, upraszczałem przykład, jedynym zmiennym parametrem byłby boolean. Pytanie polegało na wykorzystaniu zdarzeń do przekazania danych z powrotem do programu wywołującego, w zasadzie jako kanału dwukierunkowego, nie dziedziczącego EventArgs. Jedyny problem jaki widzę byłby z wieloma słuchaczami/wątkami, ale specyfikacja, w której będzie to używane, nie pozwala na to –

7

Możesz używać klasy EventArgs za pomocą podejścia Rodzajowe. W tym przykładzie użyję klasę Rect z jak Zwraca typ:

public EventHandler<Rect> SizeRectChanged; 

Podnoszenie zdarzenie:

if(SizeRectChanged != null){ 
    Rect r = new Rect(0,0,0,0); 
    SizeRectChanged(this,r); 
} 

Słuchanie wydarzenia:

anyElement.SizeRectChanged += OnSizeRectChanged; 

public void OnSizeRectChanged(object sender, Rect e){ 
    //TODO abything using the Rect class 
    e.Left = e.Top = e.Width = e.Height = 50; 
} 
+1

To nie zadziała, ponieważ EventHandler ma ograniczenie "where TEventArgs: EventArgs". Oznacza to, że typ ogólny musi pochodzić z EventArgs. Próba użycia przycisku Rect spowoduje błąd kompilatora. – BrandonLWhite

+4

Ograniczenie dziedziczenia EventArgs zostało usunięte w .net 4.5. – Dashu

Powiązane problemy