Action/Func vs Methods,有什么意义?

Jam*_*ght 31 .net c# action function func

我知道如何使用ActionFunc在.NET中,但每次我开始,使用我调用的常规旧方法可以实现完全相同的解决方案.

这排除了当一个Action或者Func被用作我无法控制的东西的参数时,比如LINQ .Where.

基本上我的问题是......为什么这些存在?他们给了我什么额外的和新的一个简单的方法不?

naw*_*fal 30

我觉得这里其他的答案谈论的是什么Action/ Func是和它的使用.我将尝试回答如何在Action/ Func和方法之间进行选择.差异首先:

1)从原始性能的角度来看,与直接方法调用相比,代表的速度较慢,但是如此令人担忧,以至于担心它是一种不好的做法.

2)方法可以有重载(具有不同签名的相同函数名)但不具有Action/ Func委托,因为它们被声明为变量,并且通过C#规则,您不能在给定范围内具有两个具有相同名称的变量.

bool IsIt() { return 1 > 2; }
bool IsIt(int i) { return i > 2; } //legal

Func<bool> IsIt = () => 1 > 2; 
Func<int, bool> IsIt = i => i > 2; //illegal, duplicate variable naming
Run Code Online (Sandbox Code Playgroud)

3)因此,Action/ Func是可重新分配的并且可以指向任何函数,而编译后的方法永远保持相同.Func/Action如果它指向的方法在运行时期间永远不会改变,那么它在语义上是错误的.

bool IsIt() { return 1 > 2; } //always returns false

Func<bool> IsIt = () => 1 > 2; 
IsIt = () => 2 > 1; //output of IsIt depends on the function it points to.
Run Code Online (Sandbox Code Playgroud)

4)您可以为常规方法指定ref/ out参数.例如,你可以拥有

bool IsIt(out string p1, ref int p2) { return 1 > 2; } //legal

Func<out string, ref int, bool> IsIt; //illegal
Run Code Online (Sandbox Code Playgroud)

5)您不能为Action/ 引入新的泛型类型参数Func(它们是通用的btw,但类型参数只能是父方法或类中指定的已知类型),与方法不同.

bool IsIt<A, R>() { return 1 > 2; } //legal

Func<bool> IsIt<A, R> = () => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)

6)方法可以有可选参数,而不是Action/ Func.

bool IsIt(string p1 = "xyz") { return 1 > 2; } //legal

Func<string, bool> IsIt = (p1 = "xyz") => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)

7)您可以params为方法的参数设置关键字,而不是Action/ Func.

bool IsIt(params string[] p1) { return 1 > 2; } //legal

Func<params string[], bool> IsIt = p1 => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)

8) Intellisense可以很好地使用方法的参数名称(因此你有很酷的XML文档可用于方法),而不是Action/ Func.因此,就可读性而言,常规方法获胜.

9) Action/Func参数限制为16(不是你不能用更多的方法定义你自己的参数),但方法支持的比你需要的多.

至于何时使用哪个,我会考虑以下几点:

  1. 当你被迫使用基于上述任何一点的那个,那么你无论如何也别无选择.第3点是我发现最引人注目的,你必须根据这个决定作出决定.

  2. 在大多数正常情况下,常规方法是可行的方法.这是在C#和VB.NET世界中重构一组通用功能的标准方法.

  3. 根据经验,如果函数不仅仅是一行,我更喜欢一种方法.

  4. 如果函数在特定方法之外没有相关性,并且函数太简单了,比如简单的selector(Func<S, T>)或谓词(Func<bool>)我更喜欢Action/ Func.例如,

    public static string GetTimeStamp() 
    {
        Func<DateTime, string> f = dt => humanReadable 
                                       ? dt.ToShortTimeString() 
                                       : dt.ToLongTimeString();
        return f(DateTime.Now);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 可能存在Action/ Func更有意义的情况.例如,如果你必须构建一个繁重的表达式并编译一个委托,那么它只需要执行一次并缓存已编译的委托.

    public static class Cache<T> 
    { 
        public static readonly Func<T> Get = GetImpl();
    
        static Func<T> GetImpl()
        {
            //some expensive operation here, and return a compiled delegate
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    代替

    public static class Cache<T> 
    {
        public static T Get()
        {
            //build expression, compile delegate and invoke the delegate
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在第一种情况下,当你调用时Get,GetImpl只执行一次,而在第二种情况下,Get每次都会调用(昂贵的).


不要忘记匿名方法本身会有一些无关的限制Func/Action,使得使用方式略有不同.另请参阅此相关问题.


Chr*_*ain 23

Action和Func是框架提供的委托类型.委托允许将函数视为变量,这意味着您可以(除其他外)将它们从方法传递给方法.如果您曾使用C++编程,则可以将Delegates视为受其引用的方法的签名限制的函数指针.

Action和Func特别是通用委托(意思是它们采用类型参数)和一些最常见的签名 - 几乎所有程序中的任何方法都可以使用这两个中的一个或另一个来表示,从而节省了人们大量时间手动定义委托我们在版本2之前的.net中做过.事实上,当我在项目中看到这样的代码时,我通常可以安全地假设项目是从.net 1.1迁移的:

// This defines a delegate (a type that represents a function)
// but usages could easily be replaced with System.Action<String>
delegate void SomeApplicationSpecificName(String someArgument);
Run Code Online (Sandbox Code Playgroud)

我建议您再考虑一下代表们.它们是C#语言的一个非常强大的功能.


Han*_*ood 7

我用它们来创建一个函数数组。例如,我可能有一个包含可以执行的操作的 ComboBox。我用类或结构的项目填充 ComboBox:

public class ComboBoxAction
{
    private string text;
    private Action method;

    public ComboBoxAction(string text, Action method)
    {
        this.text = text;
        this.method = method;
    }

    public override string ToString()
    {
        return this.text;
    }

    public void Go()
    {
        this.method();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后当有人选择一个项目时,我可以调用该操作。

CType(ComboBox1.SelectedItem, ComboBoxAction).Go()
Run Code Online (Sandbox Code Playgroud)

这比让 Select 语句根据 ComboBox 的文本确定要调用的方法要容易得多。