C #: Meningkatkan acara yang diwarisi

144

Saya memiliki kelas dasar yang berisi acara-acara berikut:

public event EventHandler Loading;
public event EventHandler Finished;

Di kelas yang mewarisi dari kelas dasar ini saya mencoba mengangkat acara:

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

Saya menerima kesalahan berikut:

Acara 'BaseClass.Loading' hanya dapat muncul di sisi kiri + = atau - = (BaseClass ')

Saya berasumsi saya tidak dapat mengakses acara ini sama dengan anggota yang diwarisi lainnya?

Jagwar
sumber
Pertanyaan ini sudah dijawab oleh Frederik Gheysels . Praktik yang sama direkomendasikan di Microsoft Documents: Cara menaikkan acara kelas dasar di kelas turunan (Panduan Pemrograman C #) sebagai "Panduan Pemrograman C #" resmi
Eliahu Aaron

Jawaban:

160

Yang harus Anda lakukan adalah ini:

Di kelas dasar Anda (tempat Anda telah mendeklarasikan acara), buat metode yang dilindungi yang dapat digunakan untuk meningkatkan peristiwa:

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);
       }
   }
}

(Perhatikan bahwa Anda mungkin harus mengubah metode-metode itu, untuk memeriksa apakah Anda harus memohon eventhandler atau tidak).

Kemudian, di kelas yang mewarisi dari kelas dasar ini, Anda bisa memanggil metode OnFinished atau OnLoading untuk meningkatkan peristiwa:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}
Frederik Gheysels
sumber
5
Metode-metode itu harus dilindungi secara virtual kecuali ada alasan untuk melakukan sebaliknya.
Max Schmeling
6
Kenapa harus virtual? Saya akan mendeklarasikan virtual jika saya ingin pewaris untuk mengubah cara acara tersebut harus ditingkatkan, tetapi sebagian besar waktu, saya tidak melihat alasan untuk melakukan hal ini ...
Frederik Gheysels
5
Mengenai membuat metode virtual, sehingga pewaris dapat menimpa perilaku acara doa: Berapa kali Anda berada dalam situasi di mana ini diperlukan? Di sebelahnya; dalam metode overriden, Anda tidak dapat meningkatkan acara, karena Anda akan mendapatkan kesalahan yang sama seperti yang disebutkan oleh TS.
Frederik Gheysels
2
@Verax Saya mengikutinya karena alasannya masuk akal, tergantung pada bagaimana saya dapat menggunakan kembali dan diperluas kode, saya memberikan pedoman resmi untuk mendukungnya .. pada saat penulisan Anda juga tampak sangat baru di .NET Verax jadi sedikit membingungkan bahwa Anda menggali ini hingga tidak setuju dengan pengalaman 7 tahun saya
meandmycode
123

Anda hanya bisa mengakses acara di kelas yang mendeklarasikan, karena .NET membuat variabel instance pribadi di belakang layar yang benar-benar menampung delegasi. Melakukan ini..

public event EventHandler MyPropertyChanged;

sebenarnya melakukan ini;

private EventHandler myPropertyChangedDelegate;

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

dan melakukan ini ...

MyPropertyChanged(this, EventArgs.Empty);

sebenarnya ini ...

myPropertyChangedDelegate(this, EventArgs.Empty);

Jadi Anda dapat (jelas) hanya mengakses variabel instance delegasi pribadi dari dalam kelas yang mendeklarasikan.

Konvensi ini untuk menyediakan sesuatu seperti ini di kelas yang mendeklarasikan ..

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

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

Anda kemudian dapat menelepon OnMyPropertyChanged(EventArgs.Empty)dari mana saja di kelas itu atau di bawah pusaka warisan untuk meminta acara tersebut.

Adam Robinson
sumber
Saya punya beberapa masalah dalam mengimplementasikan ini ... stackoverflow.com/q/10593632/328397
goodguys_activate
Saya lebih suka jawaban ini karena menjelaskan MENGAPA Anda harus menggunakan pendekatan, bukan hanya pendekatan. Kerja bagus.
cowboydan
8

Saya berasumsi saya tidak dapat mengakses acara ini sama dengan anggota yang diwarisi lainnya?

Tepat. Merupakan kebiasaan untuk menyediakan fungsi yang dilindungi OnXyzatau RaiseXyzuntuk setiap acara di kelas dasar untuk memungkinkan peningkatan dari kelas yang diwarisi. Sebagai contoh:

public event EventHandler Loading;

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

Dipanggil di kelas yang diwarisi:

OnLoading();
Konrad Rudolph
sumber
0

Anda dapat mencoba cara ini, Ini berfungsi untuk saya:

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);
    }
}
Olioul Islam Rahi
sumber
2
Perhatikan bahwa artikel ini memperingatkan untuk tidak mendeklarasikan peristiwa virtual dan menimpanya karena mengklaim kompiler tidak menangani ini dengan benar: msdn.microsoft.com/en-us/library/hy3sefw3.aspx
nirkabel publik
0

bukan untuk membangkitkan kembali utas lama tetapi kalau-kalau ada yang melihat, apa yang saya lakukan adalah

protected EventHandler myPropertyChangedDelegate;

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

Ini memungkinkan Anda mewarisi acara dalam kelas turunan sehingga Anda dapat menjalankannya tanpa harus membungkus metode sambil mempertahankan sintaks + =. Saya kira Anda masih bisa melakukannya dengan metode pembungkus jika Anda melakukannya

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
Zeraphil
sumber