zoukankan      html  css  js  c++  java
  • Delegate,Action,Func,Predicate的使用与区别

    C#4.0推出后,类似Linq,Lamda表达式等许多新的程序写法层次不穷。与之相关的Delegate,Action,Func,Predicate的使用和区别也常常让大家迷惑,此处就结合实际的应用,对其进行详细的说明。

    在书写代码时,常常会用到委托,这个在winform下较常见,但自定义Delegate时,我们常常发现Delegate必须全局可见,才能在需要的地方进行使用,而对于私有的delegate对象,在本类中进行使用,这似乎是不方便的。下边我们来看传统的Delegate的写法。

    public delegate void MyDelegate(string name);
       
    public class MyBlogBase
        {
           
    private MyDelegate mydelegate;
        }
     

    必须保证MyDelegate放在类的外边,才能在其他地方可见,并使用,Action,Func的出现改变了这一局面,这两个其实说白了就是系统定义好的Delegate,他有很多重载的方法,便于各种应用情况下的调用。他在系统的System命名空间下,因此全局可见。下文就说明Action,Action有多个重载,下文已Action<T>为例进行说明

    Action<T>:封装一个方法,该方法只有一个参数并且不返回值。其中T是可接收的任何类型。使用代码如下:

    复制代码
    public class MyBlogBase
        {   
            public string myName;
            Action<string> myAction;   
            public MyBlogBase()
            {
                //myAction = delegate(string curName) { myName = curName; };
                //myAction = new Action<string>(SetAction);
                myAction = curname => { myName = curname; };
              
            }
            private void SetAction(string name)
            {
                myName = name;
            }
        }
    复制代码

    在上例中,给出了3种使用Action的方法,方法一:采用匿名委托,方法二:指定一个实际的方法。方法三:使用Lamda表达式。以上3中用法均可运行。

    在实际应用中要比原始的定义Delegate方便,灵活。那么Func呢?

    Func<T in,T Tresult>:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。其实个人感觉,Func和Action的区别很明显,也很直接。二者都是委托,但Func能返回函数执行结果,而Action返回类型是Void,这个区别很明显,在具体的项目中,也很容易确定该使用那个。下文就说明具体Func的代码调用:

    复制代码
    public string myName;
            Func<string, string> myFunc;    
            public MyBlogBase()
            {          
                //myFunc = delegate(string curName) { return curName.ToUpper(); };
                //myFunc = new Func<string, string>(SetFunc);
                myFunc = name => { return name.ToUpper(); };       
            }     
            private string SetFunc(string name)
            {
                return name.ToUpper();
            }      
            public void StartFun(string curName)
            {
                myName = myFunc(curName);
            }
    复制代码

    如上3种写法,都是合适的Func定义,大家可以选择适合自己的编程模式,其实匿名方法,有个优点,就是可以直接使用当前函数出现的变量,代码更简洁,但可能有些人觉得不易读。

    Predicate<T>:也是一种委托,表示定义一组条件并确定指定对象是否符合这些条件的方法.此方法常在集合的查找中被用到,如:数组,正则拼配的结果集中被用到。使用此方法快捷方便,使用代码如下:

    复制代码
    Predicate<int> myPredicate;
            int[] myNum = new int[8] { 12, 33, 89, 21, 15, 29, 40, 52 };
           public int[] myResult;
            public MyBlogBase()
            {
                myPredicate = delegate(int curNum)             { if (curNum % 2 == 0) return true;               else return false;             };
            } 
            public void StartPredicate()
            {
                myResult = Array.FindAll(myNum, myPredicate);
            }
     
    复制代码

    上例中说明了Predicate的使用,FindAll方法中,参数2即是一个Predicate,在具体的执行中,每一个数组的元素都会执行指定的方法,如果满足要求返回true,并会被存放在结果集中,不符合的则被剔除,最终返回的集合,即是结果判断后想要的集合,此方法应用场景感觉像迭代中的yield。当然此方法也可以书写上边类似Action和Func的3中方式,此处省略。

    为了更好的验证运行效果,添加Test项目及进行测试,把代码粘帖出来分享一下:

    复制代码
    [TestMethod]
            public void TestAction()
            {
                MyBlogBase blogObj = new MyBlogBase();
                blogObj.StartAction("ywg369");
                Assert.AreEqual("ywg369", blogObj.myName);
            }
            [TestMethod]
            public void TestFunc()
            {
                MyBlogBase blogObj = new MyBlogBase();
                blogObj.StartFun("ywg369");
                Assert.AreEqual("YWG369", blogObj.myName);
            }
            [TestMethod]
            public void TestPredicate()
            {
                MyBlogBase blogObj = new MyBlogBase();
                blogObj.StartPredicate();
                Assert.AreEqual(3, blogObj.myResult.Length);
            }
    复制代码

    经过验证,运行良好,各个方法都按照期望的结果运行成功。通过此处对Delegate,Action,Func,Predicate的使用有个大致的了解,在具体的应用中根据

    实际情况进行调用。大家对此有什么好的建议或意见,多交流。

    其实他们两个都是委托【代理】的简写形式。

     
    一、【action<>】指定那些只有输入参数,没有返回值的委托
     
    Delegate的代码:
     
    [csharp] 
    public delegate void myDelegate(string str); 
    public static void HellowChinese(string strChinese) 
    Console.WriteLine("Good morning," + strChinese);
        Console.ReadLine(); 
     
    myDelegate d = new myDelegate(HellowChinese); 
    d("Mr wang"); 
     
    用了Action之后呢:
     
     
     
    [csharp] 
    public static void HellowChinese(string strChinese) 
        Console.WriteLine("Good morning," + strChinese); 
        Console.ReadLine(); 
     
    Action<string> action = HellowChinese; 
    action("Spring."); 
    就是相当于省去了定义委托的步骤了。
     
     
     
    二、func<> 这个和上面的那个是一样的,区别是这个有返回值!
     
    [csharp]  www.2cto.com
    public static string HelloEnglish(string strEnglish) 
        return "Hello." + strEnglish; 
     
    Func<string, string> f = HelloEnglish; 
    Console.WriteLine(f("Srping ji")); 
    Console.ReadLine(); 
     
     

    Func委托

    封装一个带有返回 TResult 参数指定的类型值的方法,它有5个重载:

    ·Func<TResult>         

    ·Func<T,TResult>    

    ·Func<T1,T2,TResult>  

    ·Func<T1,T2,T3,TResult> 

    ·Func<T1,T2,T3,T4,TResult> 

    这里用一个举例说明:以Func<T,TR>这个来说明。这个从根源讲要说到委托(delegate)。这个方法的意义是有一个T参数,且返回值类型为TR类型的方法。

    (1)按常规来做的方法为

    定义一个返回bool的方法。

    public bool IsTen(int i)
    {    
      return i == 10 ? true : false;
    }

     

    测试

    [Test]
    public void TestFun1()
    {    
      Assert.AreEqual(true, IsTen(10));
    }

     

    (2)通过委托来实现

     
    delegate bool IsTenDelegate(int i);
    public bool IsTen(int i)
    {    
      return i == 10 ? true : false;
    }
    [Test]
    public void TestFun1()
    {    
      //IsTenDelegate d = IsTen;    
      IsTenDelegate d = new IsTenDelegate(IsTen);    
      Assert.AreEqual(true, d(10));
    }
     

    这里把方法IsTen委托给了委托类型IsTenDelegate 。以下是2.0中匿名方法的实现

    (3)匿名方法

     
    [Test]
    public void TestFun1()
    {   
      IsTenDelegate  d= delegate(int i)    
      {       
        return i == 10 ? true : false;    
      };
        Assert.AreEqual(true, d(10));
    }
     

    通过匿名方法内联方式实现了委托IsTenDelegate  。然后在3.*版本中,通过lambda表达式成为内联委托的首选方法

    (4)Lambda

     

     
    [Test]
    public void TestFun1()
    {    
      IsTenDelegate d = x => x == 10 ? true : false;    
      Assert.AreEqual(true, d(10));
    }
     

    关于Lambda的内容请见我的另一篇随笔:

    http://www.cnblogs.com/jams742003/archive/2009/12/23/1630737.html

    (5)Func<T>

    public delegate TResult Func<TResult>()

     

    这里Func<T>的方法定义,它是一个delegate,所以,上边的IsTenDelegate 委托可以写成:

    Func<int, bool> d = x => x == 10 ? true : false;
    Assert.AreEqual(true, d(10));

    这就是Func,它带有返回值,且有5种重载,可以委托0-4个参数的方法。

    而Action<T>则与Func意义相近,只是不带返回值。

     

     

    Action委托

    封装一个方法,该方法不采用参数并且不返回值

    Action

    Action<T>

    Action<T1,T2>

    Action<T1,T2,T3>

    Action<T1,T2,T3,T4>

  • 相关阅读:
    python循环删除list中的元素
    Mysql主从同步原理简介
    python 3新式类的多继承
    面向对象之多态、多态性
    python的collections模块和functools模块
    Python(os和sys)使用
    javascript中的数据类型
    语法、关键保留字及变量
    使用JavaScript
    javascript的概述
  • 原文地址:https://www.cnblogs.com/itjeff/p/3361480.html
Copyright © 2011-2022 走看看