Як додати делегата до інтерфейсу C #


91

Мені потрібно мати делегатів у своєму класі.

Я хотів би використовувати інтерфейс, щоб "нагадати" мені встановити цих делегатів.

Як?

Мій клас виглядає так:

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

Мені потрібен інтерфейс, щоб змусити цих делегатів:

public interface myInterface
{
   // ?????
}

Відповіді:


142

Вони оголошують типи делегатів . Вони не належать до інтерфейсу. Події, що використовують ці типи делегатів, можуть бути в інтерфейсі:

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

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

Реалізація не буде (і не повинна) повторно оголошувати тип делегата так само, як і повторно оголошувати будь-який інший тип, що використовується в інтерфейсі.


Це просто не працює для мене. Я впевнений, що я зробив все таким чином, і тим не менше, мій обробник у моєму інтерфейсі не розпізнається. Мій клас, який реалізує інтерфейс, скаржиться, що клас не відповідає типу повернення інтерфейсу System.EventHandler.
Чакі,

1
@Chucky: Здається, вам слід задати нове запитання з коротким, але повним прикладом, що демонструє проблему. Відповідь я дав дійсно робить роботу.
Джон Скіт,

4
Я не розумів, що делегати мають такий самий рівень доступності, як класи. Я завжди думав, що їх потрібно інкапсулювати в класі.
Пурусарта

7
@Purusartha: Це не доступність - справа лише в тому, щоб делегати були типами (класами, насправді) рівно стільки, скільки інтерфейсами тощо
Джон Скіт,

29

З .NET 3.5 ви також можете використовувати делегатів System.Action без необхідності оголошувати власний тип.

Це призведе до наступного інтерфейсу:

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

   event Action Started;
}

+1. Я вважаю Action / Func набагато елегантнішим (і читабельнішим), ніж традиційні типи делегатів, і ви можете визначити їх у своєму інтерфейсі.
chrnola

2
Ця відповідь не стосується питання (як реалізувати myInterface).
lharper71

10

Просто виставляйте делегата як властивість

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

public interface IMyInterface
{       
    UpdateStatusEventHandler StatusUpdated {get; set;}    
    StartedEventHandler Started {get; set;}
}

7

Відповідь Джона Скіта правильна, я просто хочу додати примітку.

Інтерфейсів немає для того, щоб "нагадувати" вам, що робити або що включати у ваші класи. Інтерфейси - це засоби абстракції, що використовуються в об'єктно-орієнтованому програмуванні та методах проектування. Можливо, вам взагалі не потрібна декларація інтерфейсу, якщо ви не хочете бачити деякі конкретні екземпляри класів як інтерфейс в іншому місці вашої програми (Абстракція).

Якщо ви хочете застосувати деякі стандарти кодування у своєму проекті, ви можете спробувати скористатися засобами аналізу коду (наприклад, у Visual Studio) - вони дозволяють розширення, які ви можете включити, щоб додати власні правила аналізу коду.

За допомогою аналізу коду, якщо ви "забудете" додати делегатів (хоча я не бачу сенсу забувати його, так як якщо делегат не використовується, він не потрібен), ви отримаєте попередження / помилку.


1
Можливо, ви маєте рацію, але бувають випадки, коли ви робите деякі припущення, що навіть при хорошій документації важко згадати через деякий час. Я намагаюся повторно використовувати свій код, але іноді я не можу згадати, що це ядро, а що ні (коли справа стосується делегатів - мені важко бачити загальну картину ...)
Асаф,

1

Один із ваших коментарів посилався на тип повернення обробника події. Вас більше турбує тип обробника або дані, що повертаються з події? Якщо це останнє, то це може допомогти. Якщо ні, то цього рішення буде недостатньо, але може допомогти наблизити вас до того, що ви шукаєте.

Все, що вам потрібно зробити, це оголосити свої обробники подій як загальні обробники подій як в інтерфейсі, так і у вашій реалізації, і ви можете налаштувати результати повернення.

Ваш клас conrete виглядатиме так:

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

Ваш інтерфейс виглядатиме так:

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

Тепер, коли аргументи подій повертають ваші типи, ви можете підключити їх до будь-якого обраного вами обробника.

Для довідки: https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx


0

Інтерфейс, успадкований у межах вашого похідного класу, нагадуватиме вам про те, щоб визначити та пов’язати матеріали, які ви декларували в ньому.

Але ви можете також захотіти використовувати його явно, і вам все одно доведеться пов'язати його з об'єктом.

Наприклад, використовуючи шаблон інверсії управління:

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

Ви можете спробувати щось подібне.

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);
  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.