【问题标题】:Multicast delegate of type Func (with return value)?Func 类型的多播委托(带返回值)?
【发布时间】:2014-06-01 17:37:19
【问题描述】:

我有以下代码:

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!

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

【问题讨论】:

标签: c# .net


【解决方案1】:

它是否按预期工作?

至少它按规定工作。这是否是您的意图是另一回事:) 从 C# 5 规范的第 15.4 节 - 强调我的:

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

下一步:

我们不会丢失其他函数的返回值吗?

是的,目前。

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

说实话,很少见。但是,您可以使用 Delegate.GetInvocationList() 拆分多播委托:

foreach (Func<string, string> func in funcSum.GetInvocationList())
{
    Console.WriteLine(func("!"));
}

【讨论】:

  • 多播代表对事件至关重要 - 并且可能支持 Func 以保持一致性?
  • @Yoga:我并不是说多播委托毫无意义——我同意在现实世界中,函数的多播委托(非空委托)很少见的假设。传统的事件模式使用 void 委托类型。请注意,委托组合完全早于 Func ......但是,组合非无效委托的效果基本上是为了保持 IMO 的一致性。毕竟,你可以了解这些......
  • 老实说,如果我被要求提供更好的解决方案,我将无法给出答案或替代方案。此外,我们正在谈论的是微软和一个完整的专业团队,所以我并不反对(没有讽刺意味)。
【解决方案2】:

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

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 的任务在事件处理程序完成之前不会完成。

【讨论】:

    【解决方案3】:

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

    如果你想获得链上的所有结果,试试这个:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-10
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多