C #: Devralınan bir olayı yükseltme


144

Aşağıdaki olayları içeren bir temel sınıf var:

public event EventHandler Loading;
public event EventHandler Finished;

Bu temel sınıftan miras alan bir sınıfta olayı yükseltmeye çalışıyorum:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

Aşağıdaki hatayı alıyorum:

'BaseClass.Loading' olayı yalnızca + = veya - = (BaseClass ') öğesinin sol tarafında görünebilir

Bu olaylara diğer miras alınan üyelerle aynı şekilde erişemeyeceğimi varsayıyorum?


Bu soru zaten Frederik Gheysels tarafından cevaplandı . Aynı uygulama Microsoft Docs için de önerilir: Türetilmiş sınıflarda temel sınıf olaylarının (C # Programlama Kılavuzu) resmi bir "C # Programlama Kılavuzu" olarak yükseltilmesi
Eliahu Aaron

Yanıtlar:


160

Yapmanız gereken şudur:

Temel sınıfınızda (olayları bildirdiğiniz yerde), olayları yükseltmek için kullanılabilecek korumalı yöntemler oluşturun:

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

(Olay işleyicisini çağırmanız gerekip gerekmediğini kontrol etmek için muhtemelen bu yöntemleri değiştirmeniz gerektiğini unutmayın).

Ardından, bu temel sınıftan miras alan sınıflarda, olayları yükseltmek için OnFinished veya OnLoading yöntemlerini çağırabilirsiniz:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}

5
Aksi takdirde bir neden olmadıkça bu yöntemler sanal olarak korunmalıdır.
Max Schmeling

6
Neden sanal olmalı? Ben olay yükseltilmelidir şeklini değiştirmek için mirasçılar istiyorsa o sanal ilan edeceğini, ancak çoğu zaman, bunu yapmak için hiçbir neden görmüyorum ...
Frederik Gheysels


5
Yöntemin sanal hale getirilmesiyle ilgili olarak, mirasçılar olay çağırma davranışını geçersiz kılabilir: Bunun gerekli olduğu bir durumda kaç kez bulundunuz? Bunun yanında; geçersiz kılma yönteminde, etkinliği artıramazsınız, çünkü TS tarafından belirtilenle aynı hatayı alırsınız.
Frederik Gheysels

2
@Verax Ben akıl yürütme sağlam çünkü kodun ne kadar kullanılabilir ve genişletilebilir bağlı olarak bağlı, ben bunu desteklemek için resmi yönergeler sağladı .. yazma sırasında da .NET Verax çok yeni görünüyor bu yüzden 7 yıllık tecrübemle aynı fikirde
olmamanız

123

.NET, gerçekten temsilci barındıran sahnelerin arkasında özel örnek değişkenler oluşturduğundan, yalnızca bildiren sınıftaki bir olaya erişebilirsiniz. Bunu ..

public event EventHandler MyPropertyChanged;

aslında bunu yapıyor;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

ve bunu yaparken ...

MyPropertyChanged(this, EventArgs.Empty);

aslında bu ...

myPropertyChangedDelegate(this, EventArgs.Empty);

Böylece, özel delege örneği değişkenine yalnızca bildiren sınıftan erişebilirsiniz (açık bir şekilde).

Sözleşme, ilan eden sınıfta böyle bir şey sağlamaktır.

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

Daha sonra OnMyPropertyChanged(EventArgs.Empty)olayı çağırmak için o sınıfın herhangi bir yerinden veya miras heirarşisinin altından çağrı yapabilirsiniz .


Bunu uygularken bazı sorunlar yaşadım ... stackoverflow.com/q/10593632/328397
goodguys_activate

Bu cevabı, sadece yaklaşım yerine NEDEN kullanmanız gerektiğini açıkladığı için tercih ediyorum. İyi iş.
kovboydan

8

Bu olaylara diğer miras alınan üyelerle aynı şekilde erişemeyeceğimi varsayıyorum?

Tam. Korunan bir işlev sağlamak OnXyzveya RaiseXyzmiras alınan sınıflardan yükseltmeyi sağlamak için temel sınıftaki her olay için gelenekseldir . Örneğin:

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

Devralınan sınıfta denilen:

OnLoading();

0

Bu şekilde deneyebilirsiniz, Benim için çalışıyor:

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

2
Bu makalenin, sanal olayları bildirmeye ve derleyicinin bunu doğru işlemediğini iddia ettiği gibi geçersiz kılmaya karşı uyarıldığını unutmayın: msdn.microsoft.com/en-us/library/hy3sefw3.aspx
genel kablosuz

0

eski bir ipliği diriltmek için değil ama birinin bakması durumunda, yaptığım şey

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

Bu, olayı türetilmiş bir sınıfta miras almanıza olanak tanır, böylece + = sözdizimini korurken yöntemi sarmaya gerek kalmadan davet edebilirsiniz. Sanırım hala sarma yöntemleriyle yapabilirsin

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
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.