Hinzufügen eines Delegaten zu einer Schnittstelle C #

89

Ich muss einige Delegierte in meiner Klasse haben.

Ich möchte die Schnittstelle verwenden, um mich daran zu erinnern, diese Delegaten festzulegen.

Wie man?

Meine Klasse sieht so aus:

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

Ich brauche eine Schnittstelle, um diese Delegierten zu zwingen:

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

Antworten:

140

Diejenigen deklarieren delegieren Typen . Sie gehören nicht in eine Schnittstelle. Die Ereignisse, die diese Delegatentypen verwenden, können jedoch problemlos in der Benutzeroberfläche angezeigt werden:

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

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

Die Implementierung wird (und sollte) den Delegatentyp nicht erneut deklarieren, genauso wenig wie sie jeden anderen in einer Schnittstelle verwendeten Typ neu deklarieren würde.

Jon Skeet
quelle
Das funktioniert bei mir einfach nicht. Ich bin mir sicher, dass ich alles so gemacht habe, und dennoch wird mein Handler in meiner Benutzeroberfläche nicht erkannt. Meine Klasse, die die Schnittstelle implementiert, beschwert sich, dass die Klasse nicht mit dem Schnittstellentyp von System.EventHandler übereinstimmt.
Chucky
1
@Chucky: Klingt so, als ob Sie eine neue Frage mit einem kurzen, aber vollständigen Beispiel stellen sollten, das das Problem demonstriert. Die Antwort, die ich gegeben habe, funktioniert wirklich .
Jon Skeet
4
Mir war nicht klar, dass Delegierte genauso zugänglich sind wie Klassen. Ich dachte immer, dass sie in eine Klasse eingekapselt werden müssen.
Purusartha
7
@ Purusartha: Das ist keine Zugänglichkeit - das ist nur eine Frage der Delegierten, die Typen (tatsächlich Klassen) sind, genauso wie Schnittstellen usw.
Jon Skeet
29

Seit .NET 3.5 können Sie auch die System.Action-Delegaten verwenden, ohne Ihren eigenen Typ deklarieren zu müssen.

Dies würde zu folgender Schnittstelle führen:

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

   event Action Started;
}
DELUXEnized
quelle
+1. Ich finde Action / Func weitaus eleganter (und lesbarer) als herkömmliche Delegatentypen, und Sie können sie in Ihrer Benutzeroberfläche definieren.
Chrnola
2
Diese Antwort geht nicht auf die Frage ein (wie man myInterface implementiert).
lharper71
10

Stellen Sie den Delegaten einfach als Eigenschaft bereit

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

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

Jon Skeets Antwort ist richtig, ich möchte nur eine Notiz hinzufügen.

Schnittstellen sind nicht dazu da, Sie daran zu erinnern, was zu tun ist oder was Sie in Ihren Unterricht aufnehmen sollen. Schnittstellen sind Abstraktionsmittel, die in objektorientierten Programmier- und Entwurfsmethoden verwendet werden. Möglicherweise benötigen Sie überhaupt keine Schnittstellendeklaration, es sei denn, Sie möchten einige konkrete Klasseninstanzen als Schnittstelle an anderer Stelle in Ihrem Programm anzeigen (Abstraktion).

Wenn Sie einige Codierungsstandards in Ihrem Projekt durchsetzen möchten, können Sie versuchen, Code-Analyse-Tools (wie in Visual Studio) zu verwenden. Sie ermöglichen Erweiterungen, die Sie einbinden können, um Ihre eigenen Code-Analyseregeln hinzuzufügen.

Wenn Sie bei der Codeanalyse das Hinzufügen der Delegaten "vergessen" (obwohl ich nicht den Grund sehe, es zu vergessen, als ob der Delegat nicht verwendet wird, wird er nicht benötigt), erhalten Sie eine Warnung / einen Fehler.

Iravanchi
quelle
1
Sie haben vielleicht Recht, aber manchmal gehen Sie davon aus, dass es selbst bei einer guten Dokumentation nach einer Weile schwierig ist, sich daran zu erinnern. Ich versuche, meinen Code wiederzuverwenden, aber manchmal kann ich mich nicht erinnern, was der Kern ist und was nicht (wenn es um Delegierte geht - es fällt mir schwer, das große Ganze zu sehen ...)
Asaf
1

Einer Ihrer Kommentare bezog sich auf den Rückgabetyp des Ereignishandlers. Sind Sie mehr mit dem Typ des Handlers oder den Daten beschäftigt, die vom Ereignis zurückkommen? Wenn es das letztere ist, kann dies helfen. Wenn nicht, reicht diese Lösung nicht aus, kann Ihnen aber dabei helfen, näher an das heranzukommen, wonach Sie suchen.

Sie müssen lediglich Ihre Ereignishandler als generische Ereignishandler sowohl in der Benutzeroberfläche als auch in Ihrer Implementierung deklarieren und die Rückgabeergebnisse anpassen.

Ihre konkrete Klasse würde so aussehen:

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

Ihre Benutzeroberfläche würde folgendermaßen aussehen:

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

Nachdem die Ereignisargumente Ihre Typen zurückgeben, können Sie sie in jeden von Ihnen definierten Handler einbinden.

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

Reuben Soto
quelle
0

Die in Ihrer abgeleiteten Klasse geerbte Schnittstelle erinnert Sie daran, die darin deklarierten Inhalte zu definieren und zu verknüpfen.

Möglicherweise möchten Sie es aber auch explizit verwenden, und Sie müssen es dennoch einem Objekt zuordnen.

Zum Beispiel mit einem Inversion of Control-Muster:

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

Sie können so etwas versuchen.

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