Bagaimana cara menambahkan delegasi ke antarmuka C #

91

Saya perlu memiliki beberapa delegasi di kelas saya.

Saya ingin menggunakan antarmuka untuk "mengingatkan" saya untuk mengatur delegasi ini.

Bagaimana caranya?

Kelas saya terlihat seperti ini:

public class ClsPictures : myInterface
{
    // Implementing the IProcess interface
    public event UpdateStatusEventHandler UpdateStatusText;
    public delegate void UpdateStatusEventHandler(string Status);

    public event StartedEventHandler Started;
    public delegate void StartedEventHandler();
}

Saya membutuhkan antarmuka untuk memaksa delegasi tersebut:

public interface myInterface
{
   // ?????
}
Asaf
sumber

Jawaban:

142

Mereka mendeklarasikan tipe delegasi . Mereka tidak termasuk dalam sebuah antarmuka. Peristiwa yang menggunakan tipe delegasi tersebut boleh-boleh saja berada di antarmuka:

public delegate void UpdateStatusEventHandler(string status);
public delegate void StartedEventHandler();

public interface IMyInterface
{       
    event UpdateStatusEventHandler StatusUpdated;    
    event StartedEventHandler Started;
}

Implementasi tidak akan (dan tidak seharusnya) mendeklarasikan ulang jenis delegasi, seperti halnya akan mendeklarasikan ulang jenis lain yang digunakan dalam antarmuka.

Jon Skeet
sumber
Ini tidak berhasil untuk saya. Saya yakin saya telah melakukan semuanya dengan cara ini, namun, penangan saya dalam antarmuka saya tidak dikenali. Kelas saya yang mengimplementasikan antarmuka mengeluh bahwa kelas tersebut tidak cocok dengan tipe pengembalian antarmuka System.EventHandler.
Chucky
1
@Chucky: Sepertinya Anda harus mengajukan pertanyaan baru dengan contoh singkat tapi lengkap yang menunjukkan masalahnya. Jawaban yang saya berikan benar - benar berhasil.
Jon Skeet
4
Saya tidak menyadari bahwa delegasi memiliki tingkat aksesibilitas yang sama dengan kelas. Saya selalu berpikir bahwa mereka perlu dikemas dalam kelas.
Purusartha
7
@Purusartha: Itu bukan aksesibilitas - itu hanya masalah delegasi menjadi tipe (kelas, sebenarnya) seperti halnya antarmuka, dll.
Jon Skeet
29

Sejak .NET 3.5 Anda juga dapat menggunakan delegasi System.Action, tanpa perlu mendeklarasikan tipe Anda sendiri.

Ini akan menghasilkan antarmuka berikut:

public interface myInterface
{       
   // Implementing the IProcess interface
   event Action<String> UpdateStatusText;

   event Action Started;
}
DELUXEnized
sumber
+1. Saya menemukan Action / Func jauh lebih elegan (dan dapat dibaca) daripada tipe delegasi tradisional dan Anda dapat menentukannya di antarmuka Anda.
chrnola
2
Jawaban ini tidak menjawab pertanyaan (bagaimana mengimplementasikan myInterface).
lharper71
10

Tunjukkan saja delegasi sebagai properti

public delegate void UpdateStatusEventHandler(string status);
public delegate void StartedEventHandler();

public interface IMyInterface
{       
    UpdateStatusEventHandler StatusUpdated {get; set;}    
    StartedEventHandler Started {get; set;}
}
Cornet Gregory
sumber
7

Jawaban Jon Skeet benar, saya hanya ingin menambahkan catatan.

Antarmuka tidak ada untuk "mengingatkan" apa yang harus Anda lakukan, atau apa yang harus dimasukkan ke dalam kelas Anda. Antarmuka adalah sarana abstraksi, digunakan dalam pemrograman Berorientasi Objek dan metode desain. Mungkin Anda tidak memerlukan deklarasi antarmuka sama sekali, kecuali Anda ingin melihat beberapa instance kelas yang konkret sebagai antarmuka di tempat lain dalam program Anda (Abstraksi).

Jika Anda ingin menerapkan beberapa standar pengkodean dalam proyek Anda, Anda mungkin ingin mencoba menggunakan alat analisis kode (seperti di Visual Studio) - Mereka mengizinkan ekstensi, yang dapat Anda gabungkan untuk menambahkan aturan analisis kode Anda sendiri.

Menggunakan analisis kode, jika Anda "lupa" untuk menambahkan delegasi (meskipun saya tidak melihat gunanya melupakannya, seolah-olah delegasi tidak digunakan, itu tidak diperlukan) Anda akan mendapatkan peringatan / kesalahan.

Iravanchi
sumber
1
Anda mungkin benar, tetapi ada kalanya Anda membuat beberapa asumsi bahwa meskipun dengan dokumentasi yang baik, sulit untuk diingat setelah beberapa saat. Saya mencoba untuk menggunakan kembali kode saya tetapi kadang-kadang saya tidak dapat mengingat apa itu intinya dan apa yang bukan (ketika datang ke delegasi - sulit bagi saya untuk melihat gambaran besarnya ...)
Asaf
1

Salah satu komentar Anda mereferensikan jenis kembalian dari event handler. Apakah Anda lebih peduli dengan jenis penangan, atau data yang kembali dari acara? Jika yang terakhir, maka ini dapat membantu. Jika tidak, solusi ini tidak akan cukup, tetapi dapat membantu Anda lebih dekat dengan apa yang Anda cari.

Yang harus Anda lakukan adalah mendeklarasikan penangan peristiwa Anda sebagai penangan peristiwa umum di antarmuka dan implementasi Anda dan Anda bisa menyesuaikan hasil yang dikembalikan.

Kelas beton Anda akan terlihat seperti ini:

public class ClsPictures : myInterface
{
    // Implementing the IProcess interface
    public event EventHandler<UpdateStatusEventArgs> UpdateStatusText;
    //no need for this anymore: public delegate void UpdateStatusEventHandler(string Status);

    public event EventHandler<StartedEventArgs> Started;
    //no need for this anymore: public delegate void StartedEventHandler();
}

Antarmuka Anda akan terlihat seperti ini:

public interface myInterface
{
   event EventHandler<StartedEventArgs> Started;
   event EventHandler<UpdateStatusEventArgs> UpdateStatusText;
}

Sekarang event args mengembalikan tipe Anda, Anda bisa mengaitkannya di setiap handler yang Anda tentukan.

Untuk referensi: https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx

Ruben Soto
sumber
0

Antarmuka yang diwarisi dalam kelas turunan Anda akan mengingatkan Anda untuk mendefinisikan dan menghubungkan hal-hal yang Anda nyatakan di dalamnya.

Tetapi Anda mungkin juga ingin menggunakannya secara eksplisit dan Anda masih perlu mengaitkannya ke sebuah objek.

Misalnya menggunakan pola Inversi Kontrol:

class Form1 : Form, IForm {
   public Form1() {
     Controls.Add(new Foo(this));
   }

   // Required to be defined here.
   void IForm.Button_OnClick(object sender, EventArgs e) {
     ...
     // Cast qualifier expression to 'IForm' assuming you added a property for StatusBar.
     //((IForm) this).StatusBar.Text = $"Button clicked: ({e.RowIndex}, {e.SubItem}, {e.Model})";
   }
 }

Anda bisa mencoba sesuatu seperti ini.

interface IForm {
  void Button_OnClick(object sender, EventArgs e);
}


class Foo : UserControl {
  private Button btn = new Button();

  public Foo(IForm ctx) {
     btn.Name = "MyButton";
     btn.ButtonClick += ctx.Button_OnClick;
     Controls.Add(btn);
  }
}
Latensi
sumber