SORU
3 ŞUBAT 2009, Salı


Açıkça C olay işleyicileri kaldırmak için gerekli.

Birkaç olayları fazla bir Dersim var. Bu sınıfın genel olarak bildirildi ama gereken yöntemler olarak ihtiyaç duyulan bazda instanced olduğunu küresel Deklarasyonu üzerine instanced değil.

Her zaman bu sınıfın bir yöntem gereklidir, instanced ve olay işleyicileri kayıtlı. Açıkça bu yöntemi daha önce işleyicileri kapsam dışına çıkarsa olay çıkarmak için gerekli mi?

Bu yöntem, kapsam dışına çıktığında, yani gider sınıf örneği. Olay işleyicileri kapsam dışına gidiyor bu örneği ile kayıtlı bırakarak bellek ayak izi, bir ima var mı? (Eğer olay işleyicisi sınıfı artık başvurulan bir örneği olarak görmesini GC tutar mı diye merak ediyorum.)

Teşekkür ederim.

CEVAP
3 ŞUBAT 2009, Salı


Sizin durumunuzda, her şey yolunda. Hangi nesneyayınlarbu tutar olan olaylarhedeflerolay işleyicileri, canlı. Eğer var ise:

publisher.SomeEvent  = target.DoSomething;

publisher target başvuru ama tersi olmaz.

Senin durumunda, yayıncı olacak hak için çöp toplama (varsayarak başka başvurular için) yani aslında var başvuru için olay işleyicisi hedefleri yersizdir.

Zor durumda yayımcı uzun ömürlü oluyor ama abone olmak-istemiyorumbudurum işleyicileri çıkmak gerekir. Örneğin, bant genişliği değişiklikler ile ilgili bildirimleri, zaman uyumsuz abone sağlayan bazı veri aktarım hizmeti olduğunu varsayalım, ve transfer hizmeti nesnesi uzun ömürlüdür. Eğer bunu yaparsak:

BandwidthUI ui = new BandwidthUI();
transferService.BandwidthChanged  = ui.HandleBandwidthChange;
// Suppose this blocks until the transfer is complete
transferService.Transfer(source, destination);
// We now have to unsusbcribe from the event
transferService.BandwidthChanged -= ui.HandleBandwidthChange;

(Aslında olay işleyicisi sızıntı yok emin olun finally bloğu kullanmak isterdi.) Eğer iptal etmedik eğer doğru değilse, o zaman BandwidthUI en azından uzun transfer hizmeti olarak yaşayacaktı.

Şahsen ben nadiren rastlamak bu genellikle eğer ben abone olmak için olay, hedefin bu olayı yaşayan en az sürece yayıncı - bir oluşturacak kadar uzun düğmesi olan, örneğin. Bu potansiyel sorunu hakkında bilinmesi gerekenler var, ama bazı insanlar başvurular gitmek bilmiyorlar çünkü, onlar ne zaman bu konuda endişelenmenize gerek yok bence.

DÜZENLEME:Bu Jonathan Dickinson yorum cevap. Öncelikle, açıkça eşitlik davranışı vermek Delegate.Equals(object) için dokümanlar bakın.

İkincisi, burada üyelikten çıkma çalıştığını göstermek için kısa ama eksiksiz bir program

using System;

public class Publisher
{
    public event EventHandler Foo;

    public void RaiseFoo()
    {
        Console.WriteLine("Raising Foo");
        EventHandler handler = Foo;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
        else
        {
            Console.WriteLine("No handlers");
        }
    }
}

public class Subscriber
{
    public void FooHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Subscriber.FooHandler()");
    }
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo  = subscriber.FooHandler;
         publisher.RaiseFoo();
         publisher.Foo -= subscriber.FooHandler;
         publisher.RaiseFoo();
    }
}

Sonuçlar:

Raising Foo
Subscriber.FooHandler()
Raising Foo
No handlers

(Mono ve .test NET 3.5SP1.)

Daha fazla düzenleme:

Bu olay, bir yayıncı hala abone başvuru varken toplanabilir olduğunu kanıtlamak için.

using System;

public class Publisher
{
    ~Publisher()
    {
        Console.WriteLine("~Publisher");
    }

    public event EventHandler Foo;
}

public class Subscriber
{
    ~Subscriber()
    {
        Console.WriteLine("~Subscriber");
        Console.WriteLine("Foo==null ? {0}", Foo == null);
    }

    public void FooHandler(object sender, EventArgs e) {}
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo  = subscriber.FooHandler;

         Console.WriteLine("No more refs to publisher, "
               "but subscriber is alive");
         GC.Collect();
         GC.WaitForPendingFinalizers();         

         Console.WriteLine("End of Main method. Subscriber is about to "
               "become eligible for collection");
         GC.KeepAlive(subscriber);
    }
}

Sonuçlar (.NET 3.5SP1; Mono biraz tuhaf burada uslu görünüyor. Bazı zaman içine bakmak):

No more refs to publisher, but subscriber is alive
~Publisher
Foo==null ? False
End of Main method. Subscriber is about to become eligible for collection
~Subscriber

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Elefant Traks

    Elefant Trak

    5 HAZİRAN 2007
  • Jason Parker

    Jason Parker

    14 Aralık 2009
  • Joshua Benedict

    Joshua Bened

    26 EKİM 2013