C # -də hadisələr və hadisə işləyicilərini anlama

Hadisələrin məqsədi, xüsusən istifadəçi interfeyslərinin yaradılması kontekstində başa düşürəm. Hesab edirəm ki, bu hadisə yaratmaq üçün bir prototipdir:

 public void EventName(object sender, EventArgs e); 

Hadisəni işləyənlər nə edirlər, niyə onlar lazımdır və mən bunları necə yarada bilərəm?

271
29 апр. Levi Campbell tərəfindən təyin 29 Apr 2009-04-29 19:41 '09 da 19:41 'da 2009-04-29 19:41
@ 9 cavab

Hadisəni işləyənləri anlamaq üçün nümayəndələri anlamaq lazımdır. C # -də, metodu bir göstərici (və ya istinad) kimi təqdim edə bilərsiniz. Göstərici bir dəyər kimi qəbul edilə bilər, çünki bu faydalıdır.

Bir nümayəndənin mərkəzi konsepsiyası onun imza və ya formasıdır. Yəni, (1) qaytarma növü və (2) giriş arqumentləri. Misal üçün, void MyDelegate(object sender, EventArgs e) bir nümayəndə void MyDelegate(object sender, EventArgs e) , yalnız void qaytarma üsulları və objectEventArgs . Kvadrat çuxur və kvadrat kran kimi baxın. Buna görə də, bu metodların bir nümayəndə kimi eyni imza və ya forma olduğunu söyləyirik.

Buna görə, bir üsula keçid yaratmağın necə olacağını bilmək, hadisələrin məqsədləri barədə düşünün: sistemin başqa bir yerində baş verdiyi zaman bir kodun istifadəsinə məcbur etmək istəyirik - ya da "hadisəni idarə et". Bunu etmək üçün biz icra etmək istədiklərimiz üçün xüsusi üsullar yaradırıq. Deleqlər, hadisə ilə izləniləcək üsullar arasında yapışdırıcıdır. Tədbir hadisə qaldırıldıqda tədbirin göstəricilərinin "siyahısı" ni çağırış üsullarına saxlamalıdır. * Əlbəttə ki, bir metodu çağırmaq üçün, hansı dəlilləri keçməsini bilməliyik! Tədbir ilə çağırılacaq bütün xüsusi üsullar arasında "müqavilə" kimi nümayəndəliyi istifadə edirik.

Beləliklə, standart EventHandler (və bir çox digərləri) metodun xüsusi bir formasıdır (yenidən, void / object-EventArgs). Bir hadisə elan etdiyiniz zaman, bu hadisə ilə əlaqələndirici olaraq, bu hadisə ilə əlaqəli üsulun (EventHandler) hansı forma olduğunu deyirsiniz:

 //This delegate can be used to point to methods //which return void and take a string. public delegate void MyEventHandler(string foo); //This event can cause any method which conforms //to MyEventHandler to be called. public event MyEventHandler SomethingHappened; //Here is some code I want to be executed //when SomethingHappened fires. void HandleSomethingHappened(string foo) { //Do some stuff } //I am creating a delegate (pointer) to HandleSomethingHappened //and adding it to SomethingHappened list of "Event Handlers". myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened); //To raise the event within a method. SomethingHappened("bar"); 

(* Bu, .NET-də baş verən hadisələr üçün əsasdır və "sehrli" ləğv edilir - hadisə həqiqətən örtüklər altında, eyni "forma" üsullarının siyahısıdır. bu metodların siyahısı hər birini bu dəyərləri parametrlər olaraq istifadə etməyə çağırır. "Bir hadisə işləyicisinin tapşırığı yalnız metodunuzu çağırılacaq bu siyahıya əlavə etmək üçün daha gözəl və asan bir yoldur).

555
29 апр. Cavab Rex M 29 apr verilir. 2009-04-29 19:59 '09 at 7:59 pm 2009-04-29 19:59

C #, iki dəfə, delegateevent bilir. Birinci ilə başlayaq.

nümayəndə

delegate bir üsula istinad edir. Nümunə link yaratmaq kimi:

 MyClass instance = myFactory.GetInstance(); 

Bir üsula istinad yaratmaq üçün nümayəndədən istifadə edə bilərsiniz:

 Action myMethod = myFactory.GetInstance; 

İndi bu üsul referansınız olduğundan, bu üsula link vasitəsilə zəng edə bilərsiniz:

 MyClass instance = myMethod(); 

Amma nə üçün? Ayrıca doğrudan myFactory.GetInstance() . Bu halda, edə bilərsiniz. Ancaq tətbiqin qalan hissəsini myFactory ya da birbaşa myFactory.GetInstance() haqqında məlumat myFactory düşünməyin bir çox halları var.

Şübhəsiz ki, myFactory.GetInstance() ' myOfflineFakeFactory.GetInstance() ilə bir mərkəzi yerdən ( zavod üsulu deyilən model ) əvəz etmək myFactory.GetInstance() .

Model fabriki metodu

Belə ki, bir TheOtherClass sinfi TheOtherClassmyFactory.GetInstance() istifadə myFactory.GetInstance() lazımdırsa, bu nümayəndə olmadan olmadan kodu göstərəcəkdir (siz TheOtherClass in növü haqqında TheOtherClass ə danışmaq lazımdır):

 TheOtherClass toc; //... toc.SetFactory(myFactory); class TheOtherClass { public void SetFactory(MyFactory factory) { // set here } } 

Siz nümayəndələri istifadə edirsinizsə, mənim zavodun növünü açıqlamağa ehtiyac yoxdur:

border=0
 TheOtherClass toc; //... Action factoryMethod = myFactory.GetInstance; toc.SetFactoryMethod(factoryMethod); class TheOtherClass { public void SetFactoryMethod(Action factoryMethod) { // set here } } 

Beləliklə, başqa bir sinifə öz növünü ifşa etmədən istifadə etmək üçün nümayəndə verə bilərsiniz. Baxdığınız tək şey metodunuzun imzasıdır (sizdə neçə parametr var).

"Mənim üsulumun imzası", bundan əvvəl bunu necə eşitmişəm? Bəli, interfeyslər! interfeyslər bütün sinifin imzasını təsvir edir. Delegelerin yalnız bir üsulun imza olduğunu təsəvvür edin!

Arayüz və nümayəndə arasında başqa bir böyük fərq, sizin sinfi yazarkən C # "bu üsul bu cür nümayəndələri həyata keçirir" demək lazım deyil. İnterfeyslər ilə "bu sinif bu interfeysi tətbiq edir" demək lazımdır.

Bundan əlavə, bir nümayəndənin müraciəti (bəzi məhdudiyyətlərlə, aşağıda bax) bir neçə üsula ( MulticastDelegate adlanır) müraciət edə bilər. Bu, bir nümayəndənin çağırılması zamanı bir neçə açıq şəkildə əlaqəli metodların yerinə yetirilməsini nəzərdə tutur. Bir obyekt istinad hər zaman yalnız bir obyektə müraciət edə bilər.

MulticastDelegate üçün məhdudiyyətlər (imza üsulu / nümayəndəsi) heç bir geri dönüş dəyəri ( void ) olmamalıdır və açar sözlər imzalandıqda və istifadə edilmir. Şübhəsiz ki, bir ədəd verən iki üsul çağırır və eyni sayda qayıtmasını gözləmirsiniz. İmza MulticastDelegate temsilci avtomatik olaraq MulticastDelegate .

Hadisə

Hadisələr sadəcə obyektlərdən (məsələn, almaq, müəyyən etmək, nümunə sahələri xüsusiyyətləri) digər nümayəndəliklərdən nümayəndəyə üzv olmaqdır. Bununla birlikdə, bu xüsusiyyətlər əldə etməyəcəkdir; qurmaq; Bunun əvəzinə əlavə etmə; çıxarın;

Beləliklə:

  Action myField; public event Action MyProperty { add { myField += value; } remove { myField -= value; } } 

İstifadəçi interfeysi istifadə edir (WinForms)

İndi bilirik ki, bir nümayəndə bir üsula istinad edir və biz dünyanın nümayəndələrindən istinad edə biləcək üsulları bizə verə biləcəyini bilməsi üçün bir hadisə ola biləcəyimizi bilirik və biz istifadəçi interfeysinin düyməsiyik və sonra: biz (bizə qurduğumuz hadisə ilə) üsullarını qeydiyyatdan keçirmək üçün ittiham olunduqdan möcüzə olan hər kəsdən soruşa bilərik. Bizə təqdim edilən bütün metodlardan istifadə edə bilərik və nümayəndə olaraq onlara müraciət edə bilərik. Və sonra gözləyəcəyik və gözləməyəcəyik ... istifadəçi gəldikdən və bu düyməni tıkladıqdan sonra nümayəndəliyi çağırmaq üçün kifayət qədər səbəblərimiz olacaq. Və nümayəndənin bizə təqdim etdiyi bütün bu üsullara istinad etdiyindən bütün bu üsullar iştirak edəcəkdir. Bu metodların nə olduğunu bilmirik və biz bu metodun hansı sinfi tətbiq etdiyini bilmirik. Bizi maraqlandıran bir şeydir ki, kimsə tıklandığında maraqlıdır və bizi istədiyiniz imza ilə uyğun bir üsula keçid verdi.

Java

Java kimi >

90
29 апр. Cavab verilir tofi9 Apr 29 2009-04-29 20:45 '09 at 20:45 'da 2009-04-29 20:45

Aşağıda kömək edə biləcək bəzi nümunə kodları verilmişdir:

 using System; using System.Collections.Generic; using System.Text; namespace Event_Example { // First we have to define a delegate that acts as a signature for the // function that is ultimately called when the event is triggered. // You will notice that the second parameter is of MyEventArgs type. // This object will contain information about the triggered event. public delegate void MyEventHandler(object source, MyEventArgs e); // This is a class which describes the event to the class that receives it. // An EventArgs class must always derive from System.EventArgs. public class MyEventArgs : EventArgs { private string EventInfo; public MyEventArgs(string Text) { EventInfo = Text; } public string GetInfo() { return EventInfo; } } // This next class is the one which contains an event and triggers it // once an action is performed. For example, lets trigger this event // once a variable is incremented over a particular value. Notice the // event uses the MyEventHandler delegate to create a signature // for the called function. public class MyClass { public event MyEventHandler OnMaximum; private int i; private int Maximum = 10; public int MyValue { get { return i; } set { if(value <= Maximum) { i = value; } else { // To make sure we only trigger the event if a handler is present // we check the event to make sure it not null. if(OnMaximum != null) { OnMaximum(this, new MyEventArgs("You've entered " + value.ToString() + ", but the maximum is " + Maximum.ToString())); } } } } } class Program { // This is the actual method that will be assigned to the event handler // within the above class. This is where we perform an action once the // event has been triggered. static void MaximumReached(object source, MyEventArgs e) { Console.WriteLine(e.GetInfo()); } static void Main(string[] args) { // Now lets test the event contained in the above class. MyClass MyObject = new MyClass(); MyObject.OnMaximum += new MyEventHandler(MaximumReached); for(int x = 0; x <= 15; x++) { MyObject.MyValue = x; } Console.ReadLine(); } } } 
36
29 апр. Gary Willoughby Apr 29- ə cavab verdi 2009-04-29 20:58 '09 at 8:58 pm 2009-04-29 20:58

Bu, hadisə işəgötürən üçün bəyanatdır - bu hadisə tetiklendiğinde çağırılacaq üsul. Bir hadisə yaratmaq üçün bu kimi bir şey yazmalısınız:

 public class Foo { public event EventHandler MyEvent; } 

Sonra hadisəyə aşağıdakı kimi abunə ola bilərsiniz:

 Foo foo = new Foo(); foo.MyEvent += new EventHandler(this.OnMyEvent); 

OnMyEvent () ilə aşağıdakı kimi müəyyən edilir:

 private void OnMyEvent(object sender, EventArgs e) { MessageBox.Show("MyEvent fired!"); } 

Foo MyEvent tərəfindən MyEvent , OnMyEvent işleyiciniz OnMyEvent .

Siz həmişə EventArgs nümunəsini ikinci parametr kimi istifadə EventArgs . Əlavə məlumatı əlavə etmək istəyirsinizsə, EventArgs dan əldə edilən sinfi istifadə edə bilərsiniz ( EventArgs konvensiyaya EventArgs ). Məsələn, WPF-də WinForms və FrameworkElement də müəyyən edilmiş bəzi hadisələrə nəzər yetirsəniz, hadisə işləyicilərinə əlavə məlumatlar verən hadisələrin nümunələrini görə bilərsiniz.

31
29 апр. Cavab 29 dekabrda Andy tərəfindən verilir . 2009-04-29 19:46 '09 at 19:46 2009-04-29 19:46

Burada mövcud olan gözəl cavabları əlavə edin - qəbul delegate void MyEventHandler(string foo) , bu da delegate void MyEventHandler(string foo) istifadəçi delegate void MyEventHandler(string foo) ...

Derleyici, SomethingHappened hadisə üçün heyətin növünü bildiyindən bu belədir:

 myObj.SomethingHappened += HandleSomethingHappened; 

Tamamilə bərabərdir:

 myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened); 

Və işləyicilər də aşağıdakı qaydada qeydiyyatdan keçməməli ola bilərlər:

 // -= removes the handler from the event list of "listeners": myObj.SomethingHappened -= HandleSomethingHappened; 

Tamlığı üçün bir hadisə artırmaq üçün aşağıdakı kimi edilə bilər: yalnız hadisənin aid olduğu sinifdə:

 //Firing the event is done by simply providing the arguments to the event: var handler = SomethingHappened; // thread-local copy of the event if (handler != null) // the event is null if there are no listeners! { handler("Hi there!"); } 

Çağırışın təhlükəsiz olduğundan əmin olmaq üçün mövzu işleyicisinin yerli bir nüsxəsi lazımdır - aksi hallarda mövzu NullReferenceException və sonuncu hadisə işləyicisini null yoxdursa yoxlayırıq və orada " NullReferenceException " əyləncə var.


C # 6 bu model üçün yaxşı bir qısa əl təqdim etdi. Sıfır yayılma operatorunu istifadə edir.

 SomethingHappened?.Invoke("Hi there!"); 
20
27 авг. Mathieu Guindon tərəfindən verilmiş cavab 27 Avqust. 2013-08-27 04:32 '13 'da 4:32' də 2013-08-27 04:32

Hadisələr haqqında mənim anlayışım:

Delege:

İcra ediləcək metod / metodlara istinadlar saxlayan dəyişən. Bu bir dəyişən kimi üsulları keçməyə imkan verir.

Bir hadisə yaratmaq və tetiklemek üçün addımlar:

  • Tədbir nümayəndə heyəti nümunəsidir.

  • Tədbir nümayəndəlik nümunəsi olduğundan ilk olaraq nümayəndəliyi təyin etməlidir.

  • Bir hadisə tətil edildikdə yerinə yetiriləcək bir metod / metod təyin et (nümayəndəni çağır)

  • Yanğın hadisəsi (nümayəndə çağırışı)

Məsələn:

 using System; namespace test{ class MyTestApp{ //The Event Handler declaration public delegate void EventHandler(); //The Event declaration public event EventHandler MyHandler; //The method to call public void Hello(){ Console.WriteLine("Hello World of events!"); } public static void Main(){ MyTestApp TestApp = new MyTestApp(); //Assign the method to be called when the event is fired TestApp.MyHandler = new EventHandler(TestApp.Hello); //Firing the event if (TestApp.MyHandler != null){ TestApp.MyHandler(); } } } } 
11
06 авг. cavabı KE50 06 aug verilir . 2014-08-06 10:09 '14 at 10:09 2014-08-06 10:09

naşir: hadisələrin baş verdiyi yerdə. Naşir, hansı nümayəndənin hansı sinfi istifadə etdiyini və zəruri arqumentləri yaratdığını, bu arqumentləri və nümayəndəliyi özü verməlidir.

abunəçi: cavab. Abunəçi hadisələrə cavab vermə üsullarını müəyyən etməlidir. Bu üsullar nümayəndə kimi eyni arqumentləri qəbul etməlidir. Abunəçi bu üsulu yayımcı nümayəndəsinə əlavə edəcək.

Buna görə, yayımcıda bir hadisə meydana gəldiyində, nümayəndə bir sıra arqumentlər (məlumat, və s.) Alacaq, lakin yayıncı bütün bu məlumatlara nə baş verəcəyini bilmir. Abunəçilər yayımçının hadisələrinə cavab verə bilmək üçün yayımçının sinifindəki hadisələrə cavab vermək üçün siniflərdə metodlar yarada bilərlər.

3
30 сент. Cavab verildi rileyss Sep 30 2016-09-30 03:47 '16 'da 3:47 2016-09-30 03:47' də
 //This delegate can be used to point to methods //which return void and take a string. public delegate void MyDelegate(string foo); //This event can cause any method which conforms //to MyEventHandler to be called. public event MyDelegate MyEvent; //Here is some code I want to be executed //when SomethingHappened fires. void MyEventHandler(string foo) { //Do some stuff } //I am creating a delegate (pointer) to HandleSomethingHappened //and adding it to SomethingHappened list of "Event Handlers". myObj.MyEvent += new MyDelegate (MyEventHandler); 
2
29 июля '15 в 17:43 2015-07-29 17:43 Cavab 29 iyul 'da 17:43' də Bilgi Sayar tərəfindən verilir. 2015-07-29 17:43

KE50 ilə razıyam, ancaq "hadisə" sözünü ActionCollection üçün bir takma ad olaraq hesab edirəm, çünki hadisə yerinə yetirilməsi üçün tədbirlər toplusunu (yəni bir nümayəndə) ehtiva edir.

 using System; namespace test{ class MyTestApp{ //The Event Handler declaration public delegate void EventAction(); //The Event Action Collection //Equivalent to // public List<EventAction> EventActions=new List<EventAction>(); // public event EventAction EventActions; //An Action public void Hello(){ Console.WriteLine("Hello World of events!"); } //Another Action public void Goodbye(){ Console.WriteLine("Goodbye Cruel World of events!"); } public static void Main(){ MyTestApp TestApp = new MyTestApp(); //Add actions to the collection TestApp.EventActions += TestApp.Hello; TestApp.EventActions += TestApp.Goodbye; //Invoke all event actions if (TestApp.EventActions!= null){ //this peculiar syntax hides the invoke TestApp.EventActions(); //using the 'ActionCollection' idea: // foreach(EventAction action in TestApp.EventActions) // action.Invoke(); } } } } 
0
17 окт. user3902302 17 oct tərəfindən verilən cavabı . 2014-10-17 00:03 '14 'də 0:03 2014-10-17 00:03

əlaqəli haqqında digər suallar və ya bir sual