类型为Func的多播委托(具有返回值)?

时间:2014-06-01 17:37:19

标签: c# .net

我有以下代码:

Func<string, string> func1 = (param) =>
{
    Console.WriteLine("Func 1 executing");
    return "Hello" + param;
};
Func<string, string> func2 = (param) =>
{
    Console.WriteLine("Func 2 executing");
    return "World" + param;
};
Func<string, string> funcSum = func1 + func2;
string funcResult = funcSum("!");
Console.WriteLine(funcResult);

输出结果为:

Func 1 executing
Func 2 executing
World!

反转总和:

Func<string, string> funcSum = func2 + func1;

给出输出:

Func 2 executing
Func 1 executing
Hello!

我的初始测试是使用布尔返回类型完成的,返回的值也总是由最后一个函数决定。它是按预期工作的吗?我们不是在失去其他功能的回报价值吗?如果是这样,在现实世界中是否存在这些多播功能委托的用例?

3 个答案:

答案 0 :(得分:14)

  

它是否按预期工作?

它至少按照规定工作。这是不是你想要的是另一回事:)从C#5规范的第15.4节 - 强调我的:

  

通过按顺序同步调用调用列表中的每个方法来调用其调用列表包含多个条目的委托实例。所谓的每个方法都传递给委托实例的同一组参数。如果这样的委托调用包含引用参数(第10.6.1.2节),则每个方法调用都将引用同一个变量;通过调用列表中的一个方法对该变量的更改将对调用列表中的下一个方法可见。 如果委托调用包含输出参数或返回值,则它们的最终值将来自列表中最后一个委托的调用。

下一步:

  

我们不是在丢失其他功能的返回值吗?

是的,此刻。

  

如果是这样,在现实世界中是否存在这些多播功能委托的用例?

说实话,很少。但是,您可以使用Delegate.GetInvocationList()

拆分多播委托
foreach (Func<string, string> func in funcSum.GetInvocationList())
{
    Console.WriteLine(func("!"));
}

答案 1 :(得分:3)

您的大部分问题已经得到了解答,但缺少的一件事就是现实世界的用例。这是一个:异步事件处理程序。

public delegate Task AsyncEventHandler(object sender, EventArgs e);
public event AsyncEventHandler X;
public async Task OnX(EventArgs e) {
  // ...

  var @event = X;
  if (@event != null)
    await Task.WhenAll(
      Array.ConvertAll(
        @event.GetInvocationList(),
        d => ((AsyncEventHandler)d)(this, e)));
}

这允许班级的用户简单地写

myobject.X += async (sender, e) => { ... };

但该对象仍将确保OnX的任务在事件处理程序的任务完成之前不会完成。

答案 2 :(得分:2)

多播委托将始终返回最后一个函数的结果。因为没有预定义的方法来组合或链接T结果。

如果您想获得链中的所有结果,请尝试以下方法:

    var result = "!";
    foreach (Func<string, string> func in funcSum.GetInvocationList())
    {
        result = func(result);
    }