C#方法作参数——关于Action和Func的使用

前言

C#用了4年了,之前一直对“委托”这个概念不是很理解,前几天突然就豁然开朗了。所以在这里记一下,希望这不仅是对自己成长的记录,也能对小伙伴们有所帮助。

分析

C#委托,可以看成是一种函数指针,它将会非常有用当你想将某个方法作为参数传入另外一个方法时(我也想吐槽一下这样写语序有些偏英文化,但是貌似这样写会使主体表达更连贯?)。

委托可以使用delegate实现,但本文所讨论的是委托的另外两种实现方式:Action和Func。相比delegate关键字,使用Action和Func会使代码更简洁。Action和Func两者的区别在于Action没有返回值,而Func有返回值。

开始

本文将通过一个例子来介绍Action和Func的概念及使用方法。

打开VS2017,新建控制台应用,取名为ActionFuncTest,确定。

C#方法作参数——关于Action和Func的使用

将Program.cs的代码替换为下面代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ActionFuncTest
{
    class Program
    {
        static int num = 0;
        static void Main(string[] args)
        {
            StartYourShow();
            Console.Read();
        }

        static void StartYourShow()
        {
            while (num < 5)
            {
                num += 1;
                Console.WriteLine("show");
            }
            Console.WriteLine("ShowEnd");
        }

    }
}

F5运行,你将会看到的结果如下图所示:

C#方法作参数——关于Action和Func的使用

我们分析一下StartYourShow这个方法的组成,它可以看做事由3部分组成的:

  1. 不终止条件(num<5)。或者说终止条件(num>=5)

  2. 循环事件(num+=1;Console.WriteLine(“show”);)

  3. 终止后事件(Console.WriteLine(“ShowEnd”)?

从某种意义上来说, StartYourShow 这个方法,把以上三个组成元素都给写死了。如果现在提出需求,我们需要一个类似 StartYourShow ,但可以为它指定以上三个组成元素的方法,该怎么做呢?

很简单,只要把Program.cs代码替换为如下代码即可:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ActionFuncTest
{
    class Program
    {
        static int num = 0;
        static void Main(string[] args)
        {
            StartYourShow(CanEnd, Method, EndMethod);
            Console.Read();
        }

        static void StartYourShow(Func<bool> CanEnd, Action Method, Action EndMethod)
        {
            while (!CanEnd()) Method();
            EndMethod();
        }

        static bool CanEnd()
        {
            if (num >= 5) return true;
            else return false;
        }

        static void Method()
        {
            num += 1;
            Console.WriteLine("show");
        }

        static void EndMethod()
        {
            Console.WriteLine("ShowEnd");
        }

    }
}

功能是实现了,但是代码却无比繁琐。但值得开心的是,上面代码可以简化为如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ActionFuncTest
{
    class Program
    {
        static int num = 0;
        static void Main(string[] args)
        {
            Func<bool> CanEnd = () => num >= 5;
            Action Method = () => { num += 1; Console.WriteLine("show"); };
            Action EndMethod = () => Console.WriteLine("ShowEnd");
            StartYourShow(CanEnd, Method, EndMethod);
            Console.Read();
        }

        static void StartYourShow(Func<bool> CanEnd, Action Method, Action EndMethod)
        {
            while (!CanEnd()) Method();
            EndMethod();
        }

    }
}

甚至简化为以下形式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ActionFuncTest
{
    class Program
    {
        static int num = 0;
        static void Main(string[] args)
        {
            StartYourShow(
                () => num >= 5,
                () => { num += 1; Console.WriteLine("show"); },
                () => Console.WriteLine("ShowEnd"));
            Console.Read();
        }

        static void StartYourShow(Func<bool> CanEnd, Action Method, Action EndMethod)
        {
            while (!CanEnd()) Method();
            EndMethod();
        }

    }
}

到这里,关于Action和Func的基本使用,相信大家也会豁然开朗了吧。

前面说过,Action是不带返回值的,而Func是带返回值的(上面的Func表示该Func返回值为bool类型);它们还有一个相同点,就是都可以带一个或多个参数。

为了探究带参数的Action和Func,可以将Program.cs代码替换为以下代码;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ActionFuncTest
{
    class Program
    {
        static int num = 0;
        static void Main(string[] args)
        {
            StartYourShow(
                (n) => n >= 5,
                (s) => { num += 1; Console.WriteLine(s); },
                (s1,s2) => Console.WriteLine(s1+s2));
            Console.Read();
        }

        static void StartYourShow(Func<int,bool> CanEnd, Action<string> Method, Action<string,string> EndMethod)
        {
            while (!CanEnd(num)) 
                Method(DateTime.Now.TimeOfDay.ToString());
            EndMethod("Show","End");
        }

    }
}

值得注意的一点是,上面的代码中,在调用 Func<int,bool> CanEnd 时,只需要传入一个int型参数即可,它将会返回一个bool类型的值。即Func尖括号内最后一个类型代表该Func的返回类型。

结束

这篇博客总结了C#的Action和Func的使用,希望对小伙伴们有帮助。

若有不足请指正,感谢。