Func return 可以在 C# 中使用多个值吗?

Can Func return multiple values in C#?

我试过这段代码:

Func<int, int> f3 = (int x) => x * 3;
f3 += (int x) => x * 4;
Console.WriteLine(f3(5));

我希望输出是:
15
20
但是我只得到20.

您可以使用元组(.Net 4.0) return 函数中的多个值。

static void Main() { 
// Create three-item tuple. 
Tuple<int, string, bool> tuple = new Tuple<int, string, bool>(1, "cat", true); 
// Access tuple properties. 
if (tuple.Item1 == 1) { Console.WriteLine(tuple.Item1); }
 if (tuple.Item2 == "dog") { Console.WriteLine(tuple.Item2); } 
if (tuple.Item3) { Console.WriteLine(tuple.Item3); } 
}

这就是您可以 return 从函数中获取元组对象的方法。

    public  Tuple<T1,String> Create<T1>(T1 item1) { 
return new Tuple<T1>(item1,"string"); 
}

你可以说是的,函数可以 return 多值,通过 Tuple(和 ValueTuple)或 IEnumerable 等。

但在您的示例中,您想要相反的结果:运行 某些函数基于一个值。

将新函数放在同一变量中的位置,第一个函数已 运行 结束。同样在 += 中,仅从最后一个函数多播 return-值 return。

我怎么看:

var listFunctions = new List<System.Func<int, int>>();

listFunctions.Add(x => x * 3);
listFunctions.Add(x => x * 4);

listFunctions.ForEach(x => Console.WriteLine( x(5)));

首先,+=在这个上下文中只是一个语法糖,所以让我们重写代码以显示显式方法调用:

Func<int, int> f3 = x => x * 3;
f3 = (Func<int, int>)Delegate.Combine(f3, (Func<int, int>)(x => x * 4));
Console.WriteLine(f3.Invoke(5));

为什么只打印一个值而不是两个值有四个原因:

  • f3Func<int, int>,意味着它有一个 int 参数并且 return 是一个 int。你调用 f3 一次,所以你只会得到一个 int.

  • Delegate.Combine 创建一个新的多播委托,其中结合了参数的调用列表,然后将其存储到 f3。调用委托会调用其调用列表中的所有函数,并且发生这种情况,因此整个调用中只有列表中最后一个函数的 returned 值是 returned 值。

  • 您正在对单个值 (int) 调用 WriteLine,因此只打印一个整数。

  • 最接近从方法调用中 returning 多个值的方法是使用元组。 .NET 中的方法本身不能 return 多个值。

如果您尝试使用 Delegate.Combine (+=),希望能够从调用中访问所有 returned 值列表,您使用了错误的方法。 System.MulticastDelegate 不适合这种调用。

有很多方法可以解决这个问题。一种是使用函数列表(或带有函数列表的自定义 class)并分别调用它们。

另一种方法是访问调用列表中的所有委托并手动调用它们:

public static object[] AggregateInvoke(this Delegate del, params object[] args)
{
    Delegate[] invlist = del.GetInvocationList();
    object[] results = new object[invlist.Length];
    for(int i = 0; i < invlist.Length; i++)
    {
        results[i] = invlist[i].DynamicInvoke(args);
    }
    return results;
}

public static TRet[] AggregateInvoke<TArg,TRet>(this Func<TArg, TRet> del, TArg arg)
{
    Delegate[] invlist = del.GetInvocationList();
    TRet[] results = new TRet[invlist.Length];
    for(int i = 0; i < invlist.Length; i++)
    {
        results[i] = ((Func<TArg, TRet>)invlist[i]).Invoke(arg);
    }
    return results;
}

第一种方法适用于所有委托,第二种方法仅适用于您的示例中的单参数函数。我不建议使用它来代替普通调用,因为这不是通常调用委托的方式。我建议使用第一种方法。