2009-02-21 9 views
22

Muszę skopiować subskrybentów jednego wydarzenia do innego wydarzenia. Czy mogę uzyskać subskrybentów wydarzenia (np. Powracającego delegata MyEvent [0])?Jak uzyskać subskrybentów wydarzenia?

Jeśli nie jest to możliwe, użyłbym narzędzia dodawania, aby dodać uczestników do listy. Czy to byłoby najlepsze rozwiązanie?

Odpowiedz

20

Zdarzenia/delegaty C# są rozsyłane grupowo, więc delegat jest sam na liście. Od wewnątrz klasy, aby uzyskać indywidualne rozmówców, można użyć:

if(field != null) { // or the event-name for field-like events 
    // or your own event-type in place of EventHandler 
    foreach(EventHandler subscriber in field.GetInvocationList()) 
    { 
     // etc 
    } 
} 

Jednakże, aby przypisać wszystkie naraz, wystarczy użyć + = lub bezpośrednie przypisanie:

SomeType other = ... 
other.SomeEvent += localEvent; 
+0

Dzięki za wskazanie tego. To jest najlepsze dla wydarzeń w moim własnym kodzie. – weiqure

+0

Dziękuję bardzo za to. Potrzebowałem dobrego rozwiązania problemu klonowania obiektów przez serializację binarną, nie korzystającego z subskrybowanych zdarzeń, albo musiałbym wdrożyć ICloneable w kilkuset klasach. – user1039513

3

Aktualizacja (podziękowania dla komentujących): przekazanie immunitabilności oznacza, że ​​klonowanie nie ma wpływu na zlecenie.

Kiedy ktoś pisze:

myDelegate += AHandler 

całkowicie nowa instancja delegata jest tworzona i przypisane do myDelegate.

Dlatego poniższy kod będzie działał dokładnie tak samo bez połączenia klonowania.


MulticastDelegate (typ podstawowy) ma metodę klonowania.

Aby uzyskać dostęp do podstawowego uczestnika, może być konieczne uniknięcie zwykłego helpera, które generuje słowo kluczowe zdarzenia, oraz bezpośrednie zarządzanie elementami (niestandardowe dodawanie i usuwanie akcesorów).

Aby to pokazać:

 
    class Program { 
     public delegate void MyDelegate(string name); 

     public event MyDelegate EventOne; 

     public void HandlerOne(string name) { 
      Console.WriteLine("This is handler one: {0}", name); 
     } 
     public void HandlerTwo(string name) { 
      Console.WriteLine("This is handler two: {0}", name); 
     } 
     public void HandlerThree(string name) { 
      Console.WriteLine("This is handler three: {0}", name); 
     } 

     public void Run() { 
      EventOne += HandlerOne; 
      EventOne += HandlerTwo; 
      Console.WriteLine("Before clone"); 
      EventOne("EventOne"); 

      
            
 
  
             MyDelegate eventTwo = (MyDelegate)EventOne.Clone();
            
  
      MyDelegate eventTwo = EventOne; 
      Console.WriteLine("After 
            
 
  
             clone
            
 copy"); 
      EventOne("EventOne"); 
      eventTwo("eventTwo"); 

      Console.WriteLine("Change event one to show it is different"); 
      EventOne += HandlerThree; 
      EventOne("EventOne"); 
      eventTwo("eventTwo"); 
     } 

     static void Main(string[] args) { 
      (new Program()).Run(); 
     } 
    } 
+0

Sam klon jest względnie nieważny - delegaci są niezmienni, dlatego wystarczy skopiować referencje uczestnika. –

+0

O ile, tak jak w przypadku próbki, nie należy samodzielnie modyfikować oryginału ani kopii. – Richard

+0

Richard - nie, to by działało ** identycznie ** bez kroku Klonowania(). –

13

Jeśli zdarzenie jest jednym opublikowane przez inną klasę, nie można - przynajmniej nie w sposób wiarygodny. Chociaż często myślimy o zdarzeniu jako o zmiennej delegowanej, w rzeczywistości jest to tylko parę metod: dodawania i usuwania (lub subskrypcji i rezygnacji z subskrypcji).

Jeśli jest to Twój własny kod, który publikuje wydarzenie, jest to łatwe - możesz sprawić, by dodający/usuwacy użytkownicy robili to, co chcesz.

Spójrz na my article on events i sprawdź, czy to ci pomoże. Jeśli nie, podaj więcej szczegółów na temat tego, co chcesz zrobić, określając, które fragmenty kodu możesz modyfikować, a które nie.

1

W przypadku trzeba zbadać subskrybenci zdarzenia z klasy zewnętrznej:

EventHandler e = typeof(ExternalClass) 
    .GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic) 
    .GetValue(instanceOfExternalClass) as EventHandler; 
if (e != null) 
{ 
    Delegate[] subscribers = e.GetInvocationList(); 
} 
Powiązane problemy