开发者

What to use? delegate, event, or Func<T>?

开发者 https://www.devze.com 2023-02-22 22:42 出处:网络
I want to provide objects within a class library the ability to “output” messages without worrying about how it is being output. The class library could be used in a console app, a WinForm or WPF wi

I want to provide objects within a class library the ability to “output” messages without worrying about how it is being output. The class library could be used in a console app, a WinForm or WPF windows application, or a web page.

I’d originally decided that I would use a delegate to handle this. I implemented this using classes but the compiler did not like the delegate when I attempted to put the delegate into an interface that each of these objects inherent from.

I found that I could move the delegate out of the interface and then was able to compile but I'm not sure that this accomplishes what I am trying to do.. It also seems like a kludge so I wanted to ask if any of you have different ideas to accomplish this…

The Interface:

namespace Test
{
  using System;
  using System.Xml.Linq;

  public interface IAction
  {
    DisplayMessageDel开发者_Python百科egate DisplayMessage(string message);
    void Execute();
    XElement Serialize(XName elementName);
  }

  public delegate void DisplayMessageDelegate(string message);
}

From there, I'm not sure how to implement this behavior: (BTW, I know that this code will not compile...)

public class ActionClass1 : IAction
{
  // Other methods not shown...
  void Execute()
  {
    if (this.DisplayMessage != null)
    {
      this.DisplayMessage(“Hello”);
    }
  }
}

public class ConsoleClass
{
  ActionClass1 class1 = new ActionClass1();
  class1.DisplayMessage = { x =>  Console.WriteLine(x); };
}

public class WinFormClass
{
  ActionClass1 class1 = new ActionClass1();
  Class1.DisplayMessage = {x => DisplayTextBox.Text = x; };
}


If you want the ability to hook up multiple delegates to respond to a single call to Execute, I would definitely use an event. If you only want a single action to be hooked up, use an Action or a Func delegate.

For your example, one of the Action delegates should work. In your case, it would be Action<string> since your delegate takes a string argument. An Action is simply a delegate that takes zero or more arguments and returns void. It appears that you aren't returning anything, so that's why I'm suggesting Action.

You only want to use a Func<TResult> if your delegate needs to return something. The difference between Func and Action is that Func delegates have a return type, and Action delegates do not. Either of these delegates have generic versions that can take up to 16 or so arguments.

If you need more than 16 arguments on a delegate you might want to reconsider the design :)


You could do this using Action<string>.

You would not want to use Func<T>, as this is defining a delegate that takes no arguments but returns a single value of type T. Action<T>, on the other hand, is a delegate that takes a single argument of type T.

I would suggest trying:

public interface IAction
{
    Action<string> DisplayMessage { get; set; }

    void Execute();
    XElement Serialize(XName elementName);
}

Once you implemented this interface (completely), you could use it via:

public class ConsoleClass
{
    public void SomeMethod()
    {
        ActionClass1 class1 = new ActionClass1();
        class1.DisplayMessage = x => Console.WriteLine(x);
    }
}

Or:

public class ConsoleClass
{
    public void SomeMethod()
    {
        ActionClass1 class1 = new ActionClass1();
        class1.DisplayMessage = this.Print;
    }

    private void Print(string message)
    {
        Console.WriteLine(message);
    }
}

You could do the same thing with events, however, I would question this. Your API is describing an action that should occur, not an event that is happening which you are responding to - and as such, I would not recommend an event.


Your interface definition is wrong. You would need to specify it like so:

namespace Test
{
  using System;
  using System.Xml.Linq;

  public interface IAction
  {
    DisplayMessageDelegate DisplayMessage { get; set; };
    void Execute();
    XElement Serialize(XName elementName);
  }

  public delegate void DisplayMessageDelegate(string message);
}

and then implement the interface.


Here

DisplayMessageDelegate DisplayMessage(string message);

you describe method that accepts string and returns DisplayMessageDelegate. Use

 event DisplayMessageDelegate DisplayMessage;

instead.


Personally I would have though that you would be best off having an abstract base class that defined an abstract method called DisplayMessage and then extending that base class by deriving from it to alter the behaviour of the way messages are displayed.


Instead of:

DisplayMessageDelegate DisplayMessage(string message);

Do:

event Action<string> DisplayMessage;

Then use the DisplayMessage per normal, events are delegates.

0

精彩评论

暂无评论...
验证码 换一张
取 消