C#中的三种委托方式:Func委托,Action委托,Predicate委托

C#中的三种委托方式:Func委托,Action委托,Predicate委托。

Func,Action,Predicate全面解析

首先来说明Func委托,通过MSDN我们可以了解到,Func委托有如下的5种类型:

            1 *delegate TResult Func<TResult>();

C#中的三种委托方式:Func委托,Action委托,Predicate委托以及这三种委托的常见使用场景。

Func,Action,Predicate全面解析

首先来说明Func委托,通过MSDN我们可以了解到,Func委托有如下的5种类型:

            1 *delegate TResult Func<TResult>();

           
2*delegate TResult Func<T1,TResult>(T1 arg1);

           
3 *delegate TResult Func<T1,T2,TResult>(T1 arg1,T2 arg2);

           
4*delegate TResult Func<T1,T2,T3,TResult>(T1arg1, T2 arg2, T3 arg3);

           
5*delegate TResult Func<T1,T2,T3,T4,TResult>T1arg1, T2 arg2, T3 arg3, T4 arg4);

复制代码

其中(1)只能委托无参但是有返回值的函数,TResult就是其返回类型。

而(2)只能委托具有一个传入参数,有返回值的函数,T1为一个传入参数,TResult为返回类型。

3)只能委托具有二个传入参数,有返回值的函数,T1T2为两个传入参数,TResult为返回类型,(4)和(5)以此类推。

那么如何来使用呢?下面给出一个简单的几个例子:

           #region Func委托
           
           
///Func<TResult>的用法
           
///这里TResult代表函数的返回值类型
           
///只能代理返回值为TResult类型的无参函数
            Func<string> func = delegate()
            {
               
return"我是Func<TResult>委托出来的结果";
            };
            Console.WriteLine(func());
            Console.ReadKey();

           
///Func<T,TResult>的用法
           
///这里的T为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T类型,返回值为TResult类型的函数
            Func<string, string> funcOne = delegate(string s)
            {
               
return s.ToUpper();
            };
            Console.WriteLine(funcOne(
"我是Func<T,TResult>委托出来的结果"));
            Console.ReadKey();

           
///Func<T1,T2,TResult>的用法
           
///这里T1,T2为代理的函数的传入类型,TResult代表函数的返回值类型
            
///只能代理参数为T1,T2类型,返回值为TResult类型的函数
            Func<string, string, string> funcTwo = delegate(string value1, string value2)
            {
               
return value1 + "" + value2;
            };
            Console.WriteLine(funcTwo(
"我是", "Func<T1,T2,TResult>委托出来的结果"));
            Console.ReadKey();

           
#endregion

复制代码

上面代码中,我用了匿名方法来代替函数,其中delegate()代表无参函数,delegate(string s)代表有一个传入参数的函数,以下的以此类推。

      然后需要说明的就是Action委托,这个委托也是非常常用的,尤其是在涉及到线程和界面交互的时候,配合着lamada表达式使用,非常方便的实现二者的交互。后面我会提到用法。

来看看Action委托的几种表现形式:

            1 * delegatevoid Action(); 无参,无返回值

             
2* delegatevoid Action<T>(T1 arg1);

           
3* delegatevoid Action<T1,T2>(T1 arg1, T2 arg2);

           
4* delegatevoid Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);

           
5* delegatevoid Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);

复制代码

从上面可以看出,总共有5中表现形式,其中(1)既没有传入参数,也没有返回值,那么它适合代理那些无参,无返回值的函数;(2)有一个传入参数,无返回值,适合代理无参,有一个返回值的函数,(3)(4)(5)以此类推。最都容纳四个传入参数。

那么如何使用呢?下面有一些简单的例子:

          #region Action的用法
           
///Action<T>的用法
           
///这里的T为代理函数的传入类型,无返回值
            Action<string[]> action = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
               
foreach (string s in result.ToList())
                {
                    Console.WriteLine(s);
                }
            };
           
string[] str={ "charlies","nancy","alex","jimmy","selina"};
            action(str);
            Console.ReadKey();

           
#endregion

复制代码

上面的例子是通过传入的String类型的数组,找出其中包含有字符s的项,然后输出到控制台。

最后一个就是Predicate委托,这个的形式比较少一些,就是一个传入参数,返回值为bool类型,具体示例如下:

            #region Predicate
         
///bool Predicate<T>的用法
           
///输入一个T类型的参数,返回值为bool类型
            Predicate<string[]> predicate = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
               
if (result.ToList().Count > 0)
                {
                   
returntrue;
                }
               
else
                {
                   
returnfalse;
                }
            };
           
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
           
if (predicate(_value))
            {
                Console.WriteLine(
"They contain.");
            }
           
else
            {
                Console.WriteLine(
"They don't contain.");
            }
            Console.ReadKey();

           
#endregion

复制代码

上面的代码其实也是判断String数组中有没有包含s的项,有的话就在控制台打印出  They contain.没有的话就打印出They don't contain.

总结一下这三个的特点就是:

Func可以接受0个至4个传入参数,必须具有返回值

Action可以接受0个至4个传入参数,无返回值

Predicate只能接受一个传入参数,返回值为bool类型

复制代码

下面附上全部实现代码:

View Code

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

namespace DelegateIntegrateConsoleApp
{
   
class Program
    {
       
staticvoid Main(string[] args)
        {
           
#region Func委托
           
           
///Func<TResult>的用法
            
///这里TResult代表函数的返回值类型
           
///只能代理返回值为TResult类型的无参函数
            Func<string> func = delegate()
            {
               
return"我是Func<TResult>委托出来的结果";
            };
            Console.WriteLine(func());
            Console.ReadKey();

           
///Func<T,TResult>的用法
           
///这里的T为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T类型,返回值为TResult类型的函数
            Func<string, string> funcOne = delegate(string s)
            {
               
return s.ToUpper();
            };
            Console.WriteLine(funcOne(
"我是Func<T,TResult>委托出来的结果"));
            Console.ReadKey();

           
///Func<T1,T2,TResult>的用法
           
///这里T1,T2为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T1,T2类型,返回值为TResult类型的函数
            Func<string, string, string> funcTwo = delegate(string value1, string value2)
            {
               
return value1 + "" + value2;
            };
            Console.WriteLine(funcTwo(
"我是", "Func<T1,T2,TResult>委托出来的结果"));
            Console.ReadKey();

           
/*************余下的类似上面的这种操作,最多可以接受四个传入参数***************
             *delegate TResultFunc<TResult>(); 
             *delegate TResultFunc<T1,TResult>(T1 arg1);
             *delegate TResultFunc<T1,T2,TResult>(T1 arg1, T2 arg2);
             *delegate TResultFunc<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3);
             *delegate TResultFunc<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
             */


           
#endregion

           
#region Action的用法
           
///Action<T>的用法
           
///这里的T为代理函数的传入类型,无返回值
            Action<string[]> action = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
                
foreach (string s in result.ToList())
                {
                    Console.WriteLine(s);
                }
            };
           
string[] str={ "charlies","nancy","alex","jimmy","selina"};
            action(str);
            Console.ReadKey();

           
/***************余下的类似上面的这种操作,最多可以接受四个传入参数**********
             * delegate void Action();
无参,无返回值
             * delegate voidAction<T>(T1 arg1);
             * delegate voidAction<T1,T2>(T1 arg1, T2 arg2);
             * delegate voidAction<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);
             * delegate voidAction<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
             */


           
#endregion

           
#region Predicate
           
///bool Predicate<T>的用法
            
///输入一个T类型的参数,返回值为bool类型
            Predicate<string[]> predicate = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
                
if (result.ToList().Count > 0)
                {
                   
returntrue;
                }
               
else
                {
                   
returnfalse;
                }
            };
           
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
           
if (predicate(_value))
            {
                Console.WriteLine(
"They contain.");
            }
           
else
            {
                Console.WriteLine(
"They don't contain.");
            }
            Console.ReadKey();

           
#endregion

        }
    }
}

复制代码

WinFormWPF,利用Func,Action,Predicate进行线程UI交互

下面这部分主要讲解如何在WinForm中利用这些委托进行线程和界面的交互。

首先对于Func来说,由于其必须具有返回值,所以我们可以利用如下代码来实现线程和界面的交互:

        #region利用Func实现线程和界面交互
       
privatevoid AlternationUsingFunc(object text)
        {
           
//无参数,但是返回值为bool类型
            this.Invoke(new Func<bool>(delegate()
            {
                button1.Text =text.ToString();
               
returntrue; //返回值
            }));
        }

       
privatevoid AlternationUsingFuncThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingFunc);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Func的使用");
        }

       
privatevoid button1_Click(object sender, EventArgs e)
        {
            AlternationUsingFuncThread();
        }
       
#endregion

复制代码

其中

 this.Invoke(new Func<bool>(delegate()
            {
                button1.Text =text.ToString();
               
returntrue; //返回值
            }));

复制代码

这段代码中利用了Func<TResult>这种类型,也就是没有传入参数,但是有一个bool类型的返回值,然后将这个函数利用加入到线程池中,最后运行,这里我们成功的设置了button1text“Func的使用

然后,对于Action来说,由于其可以无参,无返回值,那么它的交互方式最为简便,同时也是使用最多的,先看有参的调用方式:

        #region利用Action实现线程和界面交互
       
privatevoid AlternationUsingAction(object text)
        {
            
//需要一个T类型的参数,无返回值
            this.Invoke(new Action<object>(delegate(object myText)
            {
                myText = text;
                button2.Text =text.ToString();
            }),text);
        }

       
privatevoid AlternationUsingActionThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingAction);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Action的使用");
        }

       
privatevoid button2_Click(object sender, EventArgs e)
        {
           AlternationUsingActionThread();
        }
       
#endregion

复制代码

在上面的代码示例中,我们使用了带有一个传入参数的Action委托,当然了,匿名类型delegate(object myText)匿名代理了具有一个传入参数的函数。

其实简单点来说,可以像如下方式使用:

this.Invoke((Action)(()=>
            {
                button2.Text =text.ToString();
            }));

复制代码

这样就显得非常的方便。

最后一个当然是Predicate委托,和上面类似,只是写起来麻烦一些,它需要一个传入参数,并且返回一个bool类型:

        #region利用Predicate实现线程和界面的交互
       
privatevoid AlternationUsingPrecidate(object text)
        {
           
//需要一个T类型的参数,返回bool类型
            this.Invoke(new Predicate<object>(delegate(object myText) 
            {
                myText = text;
                button3.Text =myText.ToString();
               
returntrue;   //返回值
            }),text);
        }

       
privatevoid AlternationUsingPrecidateThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingPrecidate);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Predicate的使用");
        }

       
privatevoid button3_Click(object sender, EventArgs e)
        {
           AlternationUsingPrecidateThread();
        }
       
#endregion

复制代码

具体的注释我已经写在代码中了,最后运行,能成功的将button3Text置为“Predicate的使用.”



            2*delegate TResult Func<T1,TResult>(T1 arg1);

           
3 *delegate TResult Func<T1,T2,TResult>(T1 arg1,T2 arg2);

           
4*delegate TResult Func<T1,T2,T3,TResult>(T1arg1, T2 arg2, T3 arg3);

           
5*delegate TResult Func<T1,T2,T3,T4,TResult>T1arg1, T2 arg2, T3 arg3, T4 arg4);

复制代码

其中(1)只能委托无参但是有返回值的函数,TResult就是其返回类型。

而(2)只能委托具有一个传入参数,有返回值的函数,T1为一个传入参数,TResult为返回类型。

3)只能委托具有二个传入参数,有返回值的函数,T1T2为两个传入参数,TResult为返回类型,(4)和(5)以此类推。

那么如何来使用呢?下面给出一个简单的几个例子:

           #region Func委托
           
           
///Func<TResult>的用法
           
///这里TResult代表函数的返回值类型
           
///只能代理返回值为TResult类型的无参函数
            Func<string> func = delegate()
            {
               
return"我是Func<TResult>委托出来的结果";
            };
            Console.WriteLine(func());
            Console.ReadKey();

           
///Func<T,TResult>的用法
           
///这里的T为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T类型,返回值为TResult类型的函数
            Func<string, string> funcOne = delegate(string s)
            {
               
return s.ToUpper();
            };
            Console.WriteLine(funcOne(
"我是Func<T,TResult>委托出来的结果"));
            Console.ReadKey();

           
///Func<T1,T2,TResult>的用法
           
///这里T1,T2为代理的函数的传入类型,TResult代表函数的返回值类型
            
///只能代理参数为T1,T2类型,返回值为TResult类型的函数
            Func<string, string, string> funcTwo = delegate(string value1, string value2)
            {
               
return value1 + "" + value2;
            };
            Console.WriteLine(funcTwo(
"我是", "Func<T1,T2,TResult>委托出来的结果"));
            Console.ReadKey();

           
#endregion

复制代码

上面代码中,我用了匿名方法来代替函数,其中delegate()代表无参函数,delegate(string s)代表有一个传入参数的函数,以下的以此类推。

      然后需要说明的就是Action委托,这个委托也是非常常用的,尤其是在涉及到线程和界面交互的时候,配合着lamada表达式使用,非常方便的实现二者的交互。后面我会提到用法。

来看看Action委托的几种表现形式:

            1 * delegatevoid Action(); 无参,无返回值

             
2* delegatevoid Action<T>(T1 arg1);

           
3* delegatevoid Action<T1,T2>(T1 arg1, T2 arg2);

           
4* delegatevoid Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);

           
5* delegatevoid Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);

复制代码

从上面可以看出,总共有5中表现形式,其中(1)既没有传入参数,也没有返回值,那么它适合代理那些无参,无返回值的函数;(2)有一个传入参数,无返回值,适合代理无参,有一个返回值的函数,(3)(4)(5)以此类推。最都容纳四个传入参数。

那么如何使用呢?下面有一些简单的例子:

          #region Action的用法
           
///Action<T>的用法
           
///这里的T为代理函数的传入类型,无返回值
            Action<string[]> action = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
               
foreach (string s in result.ToList())
                {
                    Console.WriteLine(s);
                }
            };
           
string[] str={ "charlies","nancy","alex","jimmy","selina"};
            action(str);
            Console.ReadKey();

           
#endregion

复制代码

上面的例子是通过传入的String类型的数组,找出其中包含有字符s的项,然后输出到控制台。

最后一个就是Predicate委托,这个的形式比较少一些,就是一个传入参数,返回值为bool类型,具体示例如下:

            #region Predicate
         
///bool Predicate<T>的用法
           
///输入一个T类型的参数,返回值为bool类型
            Predicate<string[]> predicate = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
               
if (result.ToList().Count > 0)
                {
                   
returntrue;
                }
               
else
                {
                   
returnfalse;
                }
            };
           
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
           
if (predicate(_value))
            {
                Console.WriteLine(
"They contain.");
            }
           
else
            {
                Console.WriteLine(
"They don't contain.");
            }
            Console.ReadKey();

           
#endregion

复制代码

上面的代码其实也是判断String数组中有没有包含s的项,有的话就在控制台打印出  They contain.没有的话就打印出They don't contain.

总结一下这三个的特点就是:

Func可以接受0个至4个传入参数,必须具有返回值

Action可以接受0个至4个传入参数,无返回值

Predicate只能接受一个传入参数,返回值为bool类型

复制代码

下面附上全部实现代码:

View Code

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

namespace DelegateIntegrateConsoleApp
{
   
class Program
    {
       
staticvoid Main(string[] args)
        {
           
#region Func委托
           
           
///Func<TResult>的用法
            
///这里TResult代表函数的返回值类型
           
///只能代理返回值为TResult类型的无参函数
            Func<string> func = delegate()
            {
               
return"我是Func<TResult>委托出来的结果";
            };
            Console.WriteLine(func());
            Console.ReadKey();

           
///Func<T,TResult>的用法
           
///这里的T为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T类型,返回值为TResult类型的函数
            Func<string, string> funcOne = delegate(string s)
            {
               
return s.ToUpper();
            };
            Console.WriteLine(funcOne(
"我是Func<T,TResult>委托出来的结果"));
            Console.ReadKey();

           
///Func<T1,T2,TResult>的用法
           
///这里T1,T2为代理的函数的传入类型,TResult代表函数的返回值类型
           
///只能代理参数为T1,T2类型,返回值为TResult类型的函数
            Func<string, string, string> funcTwo = delegate(string value1, string value2)
            {
               
return value1 + "" + value2;
            };
            Console.WriteLine(funcTwo(
"我是", "Func<T1,T2,TResult>委托出来的结果"));
            Console.ReadKey();

           
/*************余下的类似上面的这种操作,最多可以接受四个传入参数***************
             *delegate TResultFunc<TResult>(); 
             *delegate TResultFunc<T1,TResult>(T1 arg1);
             *delegate TResultFunc<T1,T2,TResult>(T1 arg1, T2 arg2);
             *delegate TResultFunc<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3);
             *delegate TResultFunc<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
             */


           
#endregion

           
#region Action的用法
           
///Action<T>的用法
           
///这里的T为代理函数的传入类型,无返回值
            Action<string[]> action = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
                
foreach (string s in result.ToList())
                {
                    Console.WriteLine(s);
                }
            };
           
string[] str={ "charlies","nancy","alex","jimmy","selina"};
            action(str);
            Console.ReadKey();

           
/***************余下的类似上面的这种操作,最多可以接受四个传入参数**********
             * delegate void Action();
无参,无返回值
             * delegate voidAction<T>(T1 arg1);
             * delegate voidAction<T1,T2>(T1 arg1, T2 arg2);
             * delegate voidAction<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);
             * delegate voidAction<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
             */


           
#endregion

           
#region Predicate
           
///bool Predicate<T>的用法
            
///输入一个T类型的参数,返回值为bool类型
            Predicate<string[]> predicate = delegate(string[] x)
            {
               
var result = from p in x
                            
where p.Contains("s")
                            
select p;
                
if (result.ToList().Count > 0)
                {
                   
returntrue;
                }
               
else
                {
                   
returnfalse;
                }
            };
           
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
           
if (predicate(_value))
            {
                Console.WriteLine(
"They contain.");
            }
           
else
            {
                Console.WriteLine(
"They don't contain.");
            }
            Console.ReadKey();

           
#endregion

        }
    }
}

复制代码

WinFormWPF,利用Func,Action,Predicate进行线程UI交互

下面这部分主要讲解如何在WinForm中利用这些委托进行线程和界面的交互。

首先对于Func来说,由于其必须具有返回值,所以我们可以利用如下代码来实现线程和界面的交互:

        #region利用Func实现线程和界面交互
       
privatevoid AlternationUsingFunc(object text)
        {
           
//无参数,但是返回值为bool类型
            this.Invoke(new Func<bool>(delegate()
            {
                button1.Text =text.ToString();
               
returntrue; //返回值
            }));
        }

       
privatevoid AlternationUsingFuncThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingFunc);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Func的使用");
        }

       
privatevoid button1_Click(object sender, EventArgs e)
        {
            AlternationUsingFuncThread();
        }
       
#endregion

复制代码

其中

 this.Invoke(new Func<bool>(delegate()
            {
                button1.Text =text.ToString();
               
returntrue; //返回值
            }));

复制代码

这段代码中利用了Func<TResult>这种类型,也就是没有传入参数,但是有一个bool类型的返回值,然后将这个函数利用加入到线程池中,最后运行,这里我们成功的设置了button1text“Func的使用

然后,对于Action来说,由于其可以无参,无返回值,那么它的交互方式最为简便,同时也是使用最多的,先看有参的调用方式:

        #region利用Action实现线程和界面交互
       
privatevoid AlternationUsingAction(object text)
        {
            
//需要一个T类型的参数,无返回值
            this.Invoke(new Action<object>(delegate(object myText)
            {
                myText = text;
                button2.Text =text.ToString();
            }),text);
        }

       
privatevoid AlternationUsingActionThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingAction);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Action的使用");
        }

       
privatevoid button2_Click(object sender, EventArgs e)
        {
           AlternationUsingActionThread();
        }
       
#endregion

复制代码

在上面的代码示例中,我们使用了带有一个传入参数的Action委托,当然了,匿名类型delegate(object myText)匿名代理了具有一个传入参数的函数。

其实简单点来说,可以像如下方式使用:

this.Invoke((Action)(()=>
            {
                button2.Text =text.ToString();
            }));

复制代码

这样就显得非常的方便。

最后一个当然是Predicate委托,和上面类似,只是写起来麻烦一些,它需要一个传入参数,并且返回一个bool类型:

        #region利用Predicate实现线程和界面的交互
       
privatevoid AlternationUsingPrecidate(object text)
        {
           
//需要一个T类型的参数,返回bool类型
            this.Invoke(new Predicate<object>(delegate(object myText) 
            {
                myText = text;
                button3.Text =myText.ToString();
               
returntrue;   //返回值
            }),text);
        }

       
privatevoid AlternationUsingPrecidateThread()
        {
            WaitCallback waitCallBack =
new WaitCallback(this.AlternationUsingPrecidate);
           ThreadPool.QueueUserWorkItem(waitCallBack,
"Predicate的使用");
        }

       
privatevoid button3_Click(object sender, EventArgs e)
        {
           AlternationUsingPrecidateThread();
        }
       
#endregion

复制代码

具体的注释我已经写在代码中了,最后运行,能成功的将button3Text置为“Predicate的使用.”

原文地址:https://www.cnblogs.com/wangyhua/p/4050624.html