How to add a delegate to an interface C#

2019-03-08 05:19发布

问题:

I need to have some delegates in my class.

I'd like to use the interface to "remind" me to set these delegates.

How to?

My class look like this:

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

I need an interface to force those delegates:

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

回答1:

Those are declaring delegate types. They don't belong in an interface. The events using those delegate types are fine to be in the interface though:

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

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

The implementation won't (and shouldn't) redeclare the delegate type, any more than it would redeclare any other type used in an interface.



回答2:

Since .NET 3.5 you can also use the System.Action delegates, which would result in the following interface:

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

   public event Action Started;
}


回答3:

Jon Skeet's answer is right, I just want to add a note.

Interfaces are not there for "reminding" you what to do, or what to include in your classes. Interfaces are means of abstraction, used in Object Oriented programming and design methods. Maybe you don't need an interface declaration at all, unless you want to see some concrete class instances as the interface elsewhere in your program (Abstraction).

If you want to enforce some coding standards in your project, you may want to try using code analysis tools (like in Visual Studio) - They allow extensions, that you can incorporate to add you own code analysis rules.

Using code analysis, if you "forget" to add the delegates (although I don't see the point of forgetting it, as if the delegate is not used, it's not needed) you'll get a warning / error.



回答4:

Just expose the delegate as a property

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

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


回答5:

One of your comments referenced the return type of event handler. Are you more concerned with the type of the handler, or the data coming back from the event? If it's the latter, then this may help. If not, then this solution won't be enough, but may help get you closer to what you're looking for.

All you have to do is declare your event handlers as generic event handlers in both the interface and your implementation and you can customize the return results.

Your conrete class would look like this:

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

Your interface would look like this:

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

Now that the event args are returning your types, you can hook them in any handler you define.

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



回答6:

The interface inherited within your derived class will remind you to define and link up the stuff you declared in it.

But you may also want to use it explicitly and you will still need to associate it to an object.

For example using an Inversion of Control pattern:

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

You can try something like this.

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