2012-05-24 29 views
6

Kısa süre önce arama olaylarını kolaylaştırmak için C# uzantısı yöntemlerini kullanmayı öğrendim ve daha fazlasını kullanıyorum. Son zamanlarda anlayamadığım garip bir konuya değindim ve birilerinin bunu açıklayabileceğini merak ettim.C# Uzantı Yöntemleriyle olayları işleme

Sorun, başka bir olayın olay işleyicisi olarak eventhandler uzantısı yöntemini ayarlamaya çalışırken ortaya çıkar.

Bu örnekte
public static class EventHandlerExtensions 
{ 
    public static void Raise<TEventArgs>(
     this EventHandler<TEventArgs> eventHandler, 
     object sender, TEventArgs args) where TEventArgs:EventArgs 
    { 
     if (eventHandler != null) 
     { 
      eventHandler(sender, args); 
     } 
    } 
} 

public class Test 
{ 
    private event EventHandler<EventArgs> EventA; 
    private event EventHandler<EventArgs> EventB; 

    public Test() 
    { 
     Console.WriteLine("::Start"); 
     EventB += EventA.Raise; 
     EventA += (s, a) => Console.WriteLine("Event A raised"); 
     EventB.Raise(this, EventArgs.Empty); 
     Console.WriteLine("::End"); 
    } 
} 

, Eventa EventB tetiklenmesini sonucu tetiklenen edilmelidir: Burada ne yapıyorum bir örnektir. Ancak, bu kodu çalıştırdığımda, EventB tetikler, ancak A'daki uzantı yöntemi bunun için herhangi bir dinleyici bulamaz. Etrafa sırasını değiştirirseniz

, her şey iyi çalışır:

Console.WriteLine("::Start"); 
EventA += (s, a) => Console.WriteLine("Event A raised"); 
EventB += EventA.Raise; 
EventB.Raise(this, EventArgs.Empty); 
Console.WriteLine("::End"); 

Ayrıca, lambda EventA.Raise çağırarak çalışıyor:

Console.WriteLine("::Start"); 
EventB += (s, a) => EventA.Raise(s, a); 
EventA += (s, a) => Console.WriteLine("Event A raised"); 
EventB.Raise(this, EventArgs.Empty); 
Console.WriteLine("::End"); 

Bu sadece basit bir örnek, ama ben Mümkün olan en temiz şekilde eklenen etkinlik kaynaklarının olaylarını yeniden gönderebilecek bir sınıf oluşturmaya çalışıyorum. Sadece aynı olayları yeniden göndermek için adlandırılmış yöntemler oluşturmak istemiyorum ve daha sonra olay işleyicilerinden çıkarabileceğim lambda işlevleri listelemeyi tercih etmem. Çoğunlukla, bunun neden olduğunu merak ediyorum.

Herhangi bir fikrin var mı?

+0

Abone olduğunuz birçok etkinlik işleyiciniz varsa bu çok kötü olabilir. İyi soru olsa da! :) – IAbstract

+0

Kodunuzu VS2010'da yazdığımda, Console.WriteLine ("Başlat") 'dan hemen sonra 'EventA.R' yazarak,' intelllisense uzantı yöntemini göstermiyor. Console.WriteLine ("End"); 'den hemen önce yazarsam yapar. Tuhaf. – Guillaume

cevap

4

Radeon işlevinin kapanışına EventA'nın eski değerini yakalarsınız. Bundan sonra + = değerini kullanırsanız, EventA değerini değiştirir, ancak kapanışınız hala eski bir değere sahiptir.

Kodun:

var oldEventA = EventA; 
EventB += oldEventA.Raise; // captures old value here 
// now EventA changed to new value 
EventA = oldEventA + ((s, a) => Console.WriteLine("Event A raised");) 

Aslında yükseltir kodu doğrulamak için EventB += EventA.Raise önce aşağıdaki ekleyebilirsiniz:

EventB += EventA.Raise; 
EventA += (s, a) => Console.WriteLine("Event A raised"); 

Eski temsilci olsun neden açıkça eşdeğer koduna genişletilebilir Can için eski olay A:

EventA += (s, a) => Console.WriteLine("Old Event A raised"); 
2

Temsilci nesneleri immutable vardır. Tellere çok benziyor. Bu nedenle, EventA'yı atadığınızda, yeni nesnesi oluşturursunuz. EventB hala, henüz atanmış herhangi bir olay işleyicisine sahip olmayan eski olanı hedefliyor. Sorunu gidermek için iki ifadeyi değiştirmelisiniz.