Bir olay işleyici zaten eklenmiş mi?


183

Bir nesneye bir olay işleyicinin eklenip eklenmediğini anlamanın bir yolu var mı? SQL tabanlı oturum durumunu kullanabilmemiz için bir nesne listesini oturum durumuna / dışına seri hale getiriyorum ... Listedeki bir nesnenin bir özelliği değiştiğinde, olay işleyicisinin daha önce uygun şekilde halledilmesi gereken işaretlenmesi gerekir . Ancak şimdi nesnelerin serileştirilmesi yapıldığında olay işleyicisini almıyor.

Hafif bir sıkıntıyla, nesneye erişen Get özelliğine olay işleyicisini ekledim. Şimdi çağrılıyor harika, ancak 5 kez çağrılması dışında, işleyicinin nesneye her erişildiğinde eklenmeye devam ettiğini düşünüyorum.

Sadece görmezden gelmek için yeterince güvenli, ancak işleyicinin zaten eklenmiş olup olmadığını kontrol ederek daha temiz hale getirmeyi tercih ederim, bu yüzden sadece bir kez yapıyorum.

Mümkün mü?

EDIT: Mutlaka hangi olay işleyicileri eklenir tam denetime sahip değilim, bu yüzden sadece null için kontrol yeterli değil.


Yanıtlar:


123

@Telos'un belirttiği gibi, tanımlayıcı sınıfın dışından yalnızca a +=veya a'nın sol tarafında EventHandler'ı kullanabilirsiniz -=. Bu nedenle, tanımlayıcı sınıfı değiştirme yeteneğiniz varsa, olay işleyicisinin olup olmadığını denetleyerek denetimi gerçekleştirmek için bir yöntem sağlayabilirsiniz null- öyleyse, hiçbir olay işleyicisi eklenmedi. Değilse, belki Delegate.GetInvocationList içindeki değerler arasında geçiş yapabilirsiniz . Kişi, işleyici olarak eklemek istediğiniz temsilciye eşitse, orada olduğunu bilirsiniz.

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{   
    if ( this.EventHandler != null )
    {
        foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
        {
            if ( existingHandler == prospectiveHandler )
            {
                return true;
            }
        }
    }
    return false;
}

Ve bu kolayca "değiştirilmemişse işleyiciyi ekle" olacak şekilde değiştirilebilir. Eğer olayı açığa oluyor sınıfın iç organlar erişime yoksa, keşfetmek gerekebilir -=ve+= @Lou Franco tarafından önerildiği gibi,.

Ancak, bu bilgileri kendiniz izlemenin bir yolunu bulamayacağınızı görmek için bu nesneleri devreye alma ve hizmetten çıkarma şeklinizi yeniden incelemek daha iyi olabilir.


7
Bu derlenmez, EventHandler yalnızca + = veya - = 'nin sol tarafında olabilir.
CodeRedick

2
Daha fazla açıklama üzerine oy kaldırıldı. SQL durumu burada tüm fikri hemen hemen yok ediyor ... :(
CodeRedick

1
Teşekkürler Blair ve SO arama, sadece aradığım şey (sinir bozucu olsa sınıf dışında yapamazsınız)
George Mauer

3
Sorun çoğu zaman delegeleri eşitlik için karşılaştırırken ortaya çıkar. Yani kullanmak Delegate.Equals(objA, objB)tam olarak aynı temsilci özendirdiği için kontrol etmek istiyorsanız. Aksi takdirde özellikleri ayrı ayrı karşılaştırın if(objA.Method.Name == objB.Method.Name && objA.Target.GetType().FullName == objB.Target.GetType().FullName).
Sanjay

2
Bu kod bir WinForm'da çalışmıyor. Kesinlikle ASP.NET için mi?
jp2code

213

Kısa bir süre önce benzer bir duruma geldim ve burada sadece bir kez bir etkinlik için işleyici kaydetmem gerekiyordu. İşleyici hiç kayıtlı olmasa bile, önce güvenli bir şekilde kayıttan çıkabileceğinizi ve ardından tekrar kayıt yapabileceğinizi buldum:

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;

İşleyicinizi her kaydettiğinizde bunu yaptığınızın, işleyicinizin yalnızca bir kez kaydedildiğinden emin olacağını unutmayın. Bana oldukça iyi bir uygulama gibi geliyor :)


9
Riskli görünüyor; işleyici kaldırıldıktan ve geri eklenmeden önce bir olay tetiklenirse kaçırılır.
Jimmy

27
Elbette. Yani iplik güvenli değil. Ancak bu, yalnızca normal olmayan birden fazla iş parçacığı veya benzerini çalıştırırken bir sorun olabilir. Çoğu durumda bu basitlik adına yeterince iyi olmalıdır.
alf

7
Bu beni rahatsız ediyor. Şu anda kodunuzda açık bir şekilde iş parçacığı oluşturmadığınız için bu, birden fazla iş parçacığı olmadığı veya daha sonra eklenmeyecekleri anlamına gelmez. Siz (ya da ekipteki bir başkası, muhtemelen aylar sonra) bir iş parçacığı ekler ya da hem kullanıcı arayüzüne hem de ağ bağlantısına yanıt verir etmez, bu son derece aralıklı bırakılan etkinliklerin kapısını açar.
Technophile

1
Kaldırmak ve tekrar eklemek arasındaki zaman aralığının çok küçük olduğuna inanıyorum, bu kaçırılan olayların var olması pek olası değil, ancak evet, hala mümkün.
Alisson

2
Bu bir UI vb güncelleme gibi bir şey için kullanıyorsanız, o zaman bu kadar önemsiz bir görev risk Tamam. Bu ağ paket taşıma vb için olsaydı o zaman ben kullanmak olmaz.
rulolar

18

Tek işleyici buysa, etkinliğin boş olup olmadığını kontrol edebilirsiniz, değilse işleyici eklenmiştir.

Ben eklemeden önce orada olmadığından emin olmak için - eklenmediyse bile olayı işleyicinizle güvenli bir şekilde arayabileceğinizi düşünüyorum.


3
Bu mantık, olay başka bir yerde de ele alındığında kırılacaktır.
bugged87

6

Bu örnek, eklenen tüm işleyicilere delege almak için GetInvocationList () yönteminin nasıl kullanılacağını gösterir. Belirli bir işleyici (işlev) eklenip eklenmediğini görmek için dizi kullanabilirsiniz.

public class MyClass
{
  event Action MyEvent;
}

...

MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;

...

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method

Belirli bir işlevin eklenip eklenmediğini görmek için temsilcinin Method özelliğindeki çeşitli özellikleri inceleyebilirsiniz.

Sadece bir tane takılı olup olmadığını görmek istiyorsanız, sadece null olup olmadığını test edebilirsiniz.


GetInvocationList () sınıfımın bir üyesi değil. Aslında, erişebildiğim herhangi bir nesne veya işleyici üzerinde bu yöntemi bulamıyorum ...
CodeRedick

Ben de denedim, görünüşe göre sadece sınıf içinden böyle bir olay erişebilirsiniz. Bunu genel olarak yapıyorum ve diğerlerinin de belirttiği gibi olay işleyicileri muhtemelen yine de kayboluyor. Açıklama için teşekkürler!
CodeRedick

4

Sorununuzu doğru anlarsam, daha büyük sorunlarınız olabilir. Diğer nesnelerin bu olaylara abone olabileceğini söylediniz. Nesne serileştirilip serileştirildiğinde, diğer nesneler (denetiminiz olmayanlar) olay işleyicilerini kaybeder.

Bu konuda endişe duymuyorsanız, olay işleyicinize referans vermek yeterince iyi olmalıdır. Olay işleyicilerini kaybeden diğer nesnelerin yan etkileri konusunda endişeleriniz varsa, önbellek stratejinizi yeniden düşünmek isteyebilirsiniz.


1
D'oh! Bunu düşünmemiştim bile ... asıl sorunumun kendi işleyicimin kaybolması olduğunu düşünüyor olmalıydı.
CodeRedick

2

alf'nin cevabına katılıyorum, ancak küçük bir değişiklik, kullanmak,

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }

2

Benim için çalışmanın tek yolu, etkinliği eklediğimde true olarak ayarladığım bir Boolean değişkeni oluşturmaktır. Sonra soruyorum: Değişken yanlışsa, olayı eklerim.

bool alreadyAdded = false;

Bu değişken global olabilir.

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}

0
EventHandler.GetInvocationList().Length > 0

2
liste == null olduğunda bu atmaz mı?
Boris Callens

2
olay işleyiciye sahip sınıfın dışında yalnızca - = ve + = kullanabilirsiniz. etkinliğe erişemezsiniz.
tbergelt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.