用什么?委托,事件或Func <t>?</t>

时间:2011-04-08 21:24:27

标签: c# events lambda delegates

我希望为类库中的对象提供“输出”消息的能力,而不必担心它是如何输出的。类库可以在控制台应用程序,WinForm或WPF窗口应用程序或网页中使用。

我最初决定使用委托来处理这个问题。我使用类实现了这个,但是当我试图将委托放入一个固有的每个对象的接口时,编译器不喜欢委托。

我发现我可以将代理移出界面然后能够编译但我不确定这是否能完成我想要做的事情..它看起来像是一个kludge所以我想询问是否你们中的任何一个人都有不同的想法来实现这一目标......

界面:

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

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

  public delegate void DisplayMessageDelegate(string message);
}

从那里开始,我不确定如何实现这种行为:(顺便说一下,我知道这段代码不能编译......)

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

6 个答案:

答案 0 :(得分:12)

如果您希望能够连接多个代理以响应对Execute的单个调用,我肯定会使用event。如果您只希望连接一个操作,请使用ActionFunc代理。

对于您的示例,其中一个Action代表应该工作。在您的情况下,它将是Action<string>,因为您的委托采用字符串参数。 Action只是一个委托,它接受零个或多个参数并返回void。您似乎没有返回任何内容,因此我建议Action

如果您的代表需要返回某些内容,您只想使用Func<TResult>FuncAction之间的区别在于Func个委托具有返回类型,Action个委托没有。这些代理中的任何一个都具有通用版本,最多可以包含16个参数。

如果您在委托上需要超过16个参数,则可能需要重新考虑设计:)

答案 1 :(得分:6)

您可以使用Action<string>执行此操作。

你不想使用Func<T>,因为这是定义一个不带参数但只返回类型为T的Action<T>的委托,另一方面,它是一个委托类型为T的单个参数。

我建议尝试:

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

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

完全实现此界面后,您可以通过以下方式使用它:

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

或者:

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

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

你可以对事件做同样的事情,但是,我会质疑这一点。您的API正在描述应该发生的操作,而不是您正在响应的事件 - 因此,我不推荐事件。

答案 2 :(得分:1)

您的界面定义错误。你需要像这样指定它:

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

然后实现界面。

答案 3 :(得分:1)

这里

DisplayMessageDelegate DisplayMessage(string message);

您描述了接受字符串并返回DisplayMessageDelegate的方法。 使用

 event DisplayMessageDelegate DisplayMessage;

代替。

答案 4 :(得分:0)

我个人认为你最好有一个抽象基类来定义一个名为DisplayMessage的抽象方法,然后通过派生它来扩展该基类来改变消息显示方式的行为

答案 5 :(得分:0)

而不是:

DisplayMessageDelegate DisplayMessage(string message);

执行:

event Action<string> DisplayMessage;

然后按正常使用DisplayMessage,事件是委托。