在研究 lambda 表达式时,我遇到了 Action 和 Func 代表。为什么我需要第二个,我明白,至少是为了:
Func<int, int, int> summ = (x, y) => x + y;
Console.WriteLine(summ(10,20));
但是为什么你需要一个空的Action<T>还不清楚。
举一个简单的例子为什么可能需要它?例如,为什么你不能放入void和Func<T, TResult>得到相同的Action<T>种类 Func<int, void>?
有两个世界——纯函数式编程的世界和现实世界。
在纯函数式编程的纯世界中,没有可变状态,也没有语句,一切都是表达式。在这个理想世界中,函数没有副作用,编程语言中的任何构造都是表达式(即返回结果)。
但在现实世界中,情况有所不同。
在现实世界中,尤其是在 C# 的世界中,有副作用,也有一种奇妙的类型
Void,即不兼容其他类型的不常见类型。在这个世界上,一个动作 (Action) 不能用一个函数 (Func) 来表示,只是因为它是被Func<T, void>禁止的,而且没有类型Unit(类似于 typeVoid,但可以转换为泛型 typeT)。如果不是这种情况,则以下代码将有效:这并不意味着这个规则对于现实世界的所有语言都是通用的,甚至对于.NET 世界也是如此,但是对于 C# 来说是。同样的F#(一种更接近数学世界的语言)有类型
Unit,可以自动将.NET转换为.NETVoid,Unit这使得上面的代码有效。长话短说;博士;
Func<int, void>由于历史原因被禁止(很遗憾),因为很多时候你必须隔离转换器,它将转换Func<T>为Action并丢弃结果。如果我们说的是真实场景,那么
Action类型的适用性是没有问题的。Parallel.For/Parallel.ForEach:Parallel.For(0, list.Count, n => Console.WriteLine(list[n]);类似于前一个 -
ActionBlock<T>并且应该由合理数量的线程执行的操作。Task以及要异步执行的操作:var task = Task.Run(() => SomeOperation());用于日志记录和其他不返回任何内容的操作的各种回调。
一般来说,void-return 函数的存在和普及决定了
Action<T>. 好吧,我们应该尽量将副作用保持在一个合理的最小值,但在现实世界中,这个最小值永远不会变为 0。