Action、Func、Predicate 和 Converter 泛型委托详解 .

Action 委托

封装一个方法,该方法不具有参数并且不返回值。

public delegate void Action()

可以使用此委托,而不用显式声明一个自定义的委托来封装方法。该封装的方法必须与此委托定义的方法签名相对应。这意味着该方法不得具有参数和返回值。例:

  1. using System;  
  2. using System.Windows.Forms;  
  3. public class Name  
  4. {  
  5.    private string instanceName;  
  6.    public Action ShowName;  
  7.    public Show()  
  8. {  
  9.    If(ShowName != null)  
  10.     ShowName();  
  11. }  
  12.    public Name(string name)  
  13.    {  
  14.       this.instanceName = name;  
  15.    }  
  16.   
  17.    public void DisplayToConsole()  
  18.    {  
  19.   
  20.       Console.WriteLine(this.instanceName);  
  21.    }  
  22.   
  23.    public void DisplayToWindow()  
  24.    {  
  25.   
  26.       MessageBox.Show(this.instanceName);  
  27.    }  
  28.   
  29. }  
  30.   
  31. public class ActionStudy  
  32. {  
  33.    public static void Main()  
  34.    {  
  35.       Name testName = new Name("Koani");  
  36.       testName.ShowName  = () => testName.DisplayToWindow();  
  37.       testName.Show();  
  38.    }  
  39. }  
using System;
using System.Windows.Forms;
public class Name
{
   private string instanceName;
   public Action ShowName;
   public Show()
{
   If(ShowName != null)
    ShowName();
}
   public Name(string name)
   {
      this.instanceName = name;
   }

   public void DisplayToConsole()
   {

      Console.WriteLine(this.instanceName);
   }

   public void DisplayToWindow()
   {

      MessageBox.Show(this.instanceName);
   }

}

public class ActionStudy
{
   public static void Main()
   {
      Name testName = new Name("Koani");
      testName.ShowName  = () => testName.DisplayToWindow();
      testName.Show();
   }
}

Action<T> 委托

public delegate void Action<T>( T obj ) 

       Action<T> 泛型委托:封装一个方法,该方法只采用一个参数并且不返回值。可以使用此委托以参数形式传递方法,而不用显式声明自定义的委托。该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数(泛型参数),并且不能返回值。

  1. using System;  
  2. using System.Windows.Forms;  
  3.   
  4. public class ActionStudy  
  5. {  
  6.    public static void Main()  
  7.    {  
  8.       Action<string> messageTarget;   
  9.       if (Environment.GetCommandLineArgs().Length > 1)  
  10.          messageTarget = s => MessageBox.Show(s);   
  11.       else  
  12.          messageTarget = s => Console.WriteLine(s);   
  13.   
  14.       messageTarget("Hello, World!");  
  15.    }  
  16. }  
using System;
using System.Windows.Forms;

public class ActionStudy
{
   public static void Main()
   {
      Action<string> messageTarget; 
      if (Environment.GetCommandLineArgs().Length > 1)
         messageTarget = s => MessageBox.Show(s); 
      else
         messageTarget = s => Console.WriteLine(s); 

      messageTarget("Hello, World!");
   }
}

下面的示例演示如何使用 Action(T)委托来打印List(T)对象的内容。在此示例中,使用 Print 方法将列表的内容显示到控制台上。此外,C#示例还演示如何使用匿名方法将内容显示到控制台上。

  1. using System;  
  2. using System.Collections.Generic;   
  3.   
  4. class Program  
  5. {  
  6.     static void Main()  
  7.     {  
  8.         Action<string> PrintInConsole = s => Console.WriteLine(s);  
  9.         Action<string> PrintInDialog = s=>MessageBox.Show(s);  
  10.         List<String> names = new List<String>();  
  11.         names.Add("Bruce");  
  12.         names.Add("Alfred");  
  13.         names.Add("Tim");  
  14.         names.Add("Richard");  
  15.         names.ForEach(PrintInConsole);  
  16.         names.ForEach(PrintInDialog);         
  17.     }  
  18. }  
using System;
using System.Collections.Generic; 

class Program
{
    static void Main()
    {
        Action<string> PrintInConsole = s => Console.WriteLine(s);
        Action<string> PrintInDialog = s=>MessageBox.Show(s);
        List<String> names = new List<String>();
        names.Add("Bruce");
        names.Add("Alfred");
        names.Add("Tim");
        names.Add("Richard");
        names.ForEach(PrintInConsole);
        names.ForEach(PrintInDialog);       
    }
}

 

泛型委托与直接显示声明自定义委托的示例比较:

1:显示声明自定义委托:

  1. delegate void DisplayMessage(string message);  
  2. public class TestCustomDelegate  
  3. {  
  4.    public static void Main()  
  5.    {  
  6.       DisplayMessage messageTarget;   
  7.       messageTarget = ShowWindowsMessage;  
  8.       messageTarget("Hello, World!");     
  9.    }        
  10.    private static void ShowWindowsMessage(string message)  
  11.    {  
  12.       MessageBox.Show(message);        
  13.    }  
  14. }  
delegate void DisplayMessage(string message);
public class TestCustomDelegate
{
   public static void Main()
   {
      DisplayMessage messageTarget; 
      messageTarget = ShowWindowsMessage;
      messageTarget("Hello, World!");   
   }      
   private static void ShowWindowsMessage(string message)
   {
      MessageBox.Show(message);      
   }
}

 

 2: Action<T> 用法。比起自定义委托,明显可以看出代码简洁了。

  1. public class TestAction1  
  2. {  
  3.    public static void Main()  
  4.    {  
  5.       Action<string> messageTarget;   
  6.      messageTarget = ShowWindowsMessage;  
  7.       messageTarget("Hello, World!");     
  8.    }        
  9.    private static void ShowWindowsMessage(string message)  
  10.    {  
  11.       MessageBox.Show(message);        
  12.    }  
  13. }  
public class TestAction1
{
   public static void Main()
   {
      Action<string> messageTarget; 
     messageTarget = ShowWindowsMessage;
      messageTarget("Hello, World!");   
   }      
   private static void ShowWindowsMessage(string message)
   {
      MessageBox.Show(message);      
   }
}

 

Action<T1, T2> 委托

        封装一个方法,该方法具有两个参数并且不返回值。

可以使用 Action(T1, T2) 委托以参数形式传递方法,而不用显式声明自定义的委托。该

方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有两个均通过值传递给它的参数,并且不能返回值。

public delegate void Action<T,T2>(T1 arg1,T2 arg2)

 

 

  1. using System;  
  2. using System.IO;  
  3.   
  4. public class ActinStudy  
  5. {  
  6.   public static void Main()  
  7.   {  
  8.       string message1 = "The first line of a message.";  
  9.       string message2 = "The second line of a message.";  
  10.       Action<stringstring>  concat;   
  11.   
  12.       if (Environment.GetCommandLineArgs().Length > 1)  
  13.          concat = (s1, s2) => {  
  14.            StreamWriter writer = null;   
  15.            try  
  16.            {  
  17.              writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);  
  18.              writer.WriteLine("{0}"n{1}", s1, s2);  
  19.            }  
  20.            catch  
  21.            {  
  22.              Console.WriteLine("File write operation failed...");  
  23.            }  
  24.            finally  
  25.            {  
  26.              if (writer != null) writer.Close();  
  27.            }  
  28.          };  
  29.       else  
  30.          concat = (s1, s2) => Console.WriteLine("{0}"n{1}", s1, s2);  
  31.          concat(message1, message2);  
  32.    }  
using System;
using System.IO;

public class ActinStudy
{
  public static void Main()
  {
      string message1 = "The first line of a message.";
      string message2 = "The second line of a message.";
      Action<string, string>  concat; 

      if (Environment.GetCommandLineArgs().Length > 1)
         concat = (s1, s2) => {
           StreamWriter writer = null; 
           try
           {
             writer = new StreamWriter(Environment.GetCommandLineArgs()[1], false);
             writer.WriteLine("{0}"n{1}", s1, s2);
           }
           catch
           {
             Console.WriteLine("File write operation failed...");
           }
           finally
           {
             if (writer != null) writer.Close();
           }
         };
      else
         concat = (s1, s2) => Console.WriteLine("{0}"n{1}", s1, s2);
         concat(message1, message2);
   }

 

4.      3个输入参数返回值为void的委托

Action<T1,T2,T3>委托,封装一个方法,该方法采用三个参数并且不返回值。

可以使用 Action(T1, T2, T3) 委托以参数形式传递方法,而不用显式声明自定义的委托。

该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有三个均通过值传递给它的参数,并且不能返回值。

 public delegate void Action<T1,T2,T3>(T1 arg1,T2 arg2,T3 arg3);

 

5.      4个输入参数返回值为void的委托

Action<T1,T2,T3,T4>委托,封装一个方法,该方法具有四个参数并且不返回值。

可以使用 Action(T1, T2, T3, T4)委托以参数形式传递方法,而不用显式声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有四个均通过值传递给它的参数,并且不能返回值。

 

Func泛型委托

Func系列的委托定义的是返回值的委托。它有多个版本包括没有输入参数,1个输入参数,2个输入参数,3个输入参数,4个输入参数共5个版本这几个版本的原型如下:

 

Func<TResult> 委托

没有输入参数有返回值(返回值不为void)的委托。封装一个不具有参数但却返回 TResult参数指定的类型值的方法。
可以使用此委托构造一个能以参数形式传递的方法,而不用显式声明自定义的委托。该

方法必须与此委托定义的方法签名相对应。这意味着封装的方法不得具有参数,但必须返回值。

TResult:此委托封装的方法的返回值类型。
public delegate TResult Func<out TResult>()

 

Func< T,TResult> 委托

封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。 

public delegate TResult Func<T, out TResult>(T arg)

下面通过几个例子对比下,就容易知道其用法:

以下例子演示了如何利用委托将字符串转化为大写:

 

  1. delegate string ConvertMethod(string inString);  
  2.   
  3.  private static string UppercaseString(string inputString)  
  4.  {  
  5.      return inputString.ToUpper();  
  6.  }  
  7.   
  8.  protected void Page_Load(object sender, EventArgs e)  
  9.  {         
  10.      //ConvertMethod convertMeth = UppercaseString; 也可以这样写   
  11.      ConvertMethod convertMeth = new ConvertMethod(ppercaseString);  
  12.      string name = "Dakota";  
  13.      Response.Write(convertMeth(name));//通过委托调用UppercaseString方法   
  14.  }  
   delegate string ConvertMethod(string inString);

    private static string UppercaseString(string inputString)
    {
        return inputString.ToUpper();
    }

    protected void Page_Load(object sender, EventArgs e)
    {       
        //ConvertMethod convertMeth = UppercaseString; 也可以这样写
        ConvertMethod convertMeth = new ConvertMethod(ppercaseString);
        string name = "Dakota";
        Response.Write(convertMeth(name));//通过委托调用UppercaseString方法
    }


这段代码很容易理解,定义一个方法UppercaseString,功能很简单:将字符串转化为大写,然后定义一个ConvertMethod的实例来调用这个方法,最后将Dakota转化为大写输出

接下来改进一下,将Page_Load中的 ConvertMethod convertMeth = new ConvertMethod(ppercaseString)改为Func 泛型委托,即:

  1. protected void Page_Load(object sender, EventArgs e)  
  2. {  
  3.    Func<stringstring> convertMeth = UppercaseString;  
  4.    string name = "Dakota";  
  5.    Response.Write(convertMeth(name));    
  6. }  
protected void Page_Load(object sender, EventArgs e)
{
   Func<string, string> convertMeth = UppercaseString;
   string name = "Dakota";
   Response.Write(convertMeth(name));  
}

运行后,与前一种写法结果完全相同,这里再联系官方解释想一想,Func<string, string>即为封闭一个string类型的参数,并返回string类型值的方法

当然,我们还可以利用匿名委托,将这段代码写得更简洁:

  1. protected void Page_Load(object sender, EventArgs e)  
  2. {  
  3.     Func<stringstring> convertMeth = delegate(string s){ return s.ToUpper(); };  
  4.     string name = "Dakota";  
  5.     Response.Write(convertMeth(name));  
  6. }  
  7.      
protected void Page_Load(object sender, EventArgs e)
{
    Func<string, string> convertMeth = delegate(string s){ return s.ToUpper(); };
    string name = "Dakota";
    Response.Write(convertMeth(name));
}
   

怎么样?是不是清爽很多了,但这并不是最简洁的写法,如果利用Lambda表达式,还可以再简化:

  1. protected void Page_Load(object sender, EventArgs e)  
  2. {  
  3.    Func<stringstring> convertMeth = s => s.ToUpper();  
  4.    string name = "Dakota";  
  5.    Response.Write(convertMeth(name));  
  6. }  
protected void Page_Load(object sender, EventArgs e)
{
   Func<string, string> convertMeth = s => s.ToUpper();
   string name = "Dakota";
   Response.Write(convertMeth(name));
}

在linq to sql中其实大量使用了Func<T, TResult>这一泛型委托,下面的例子是不是会觉得很熟悉:

  1. protected void Page_Load(object sender, EventArgs e)  
  2. {  
  3.     Func<stringstring> convertMeth = str => str.ToUpper();          
  4.     string[] words = { "orange""apple""Article""elephant" };          
  5.     IEnumerable<String> aWords = words.Select(convertMeth);  
  6.     foreach (String s in aWords)  
  7.     {  
  8.        Response.Write(s + "<br/>");  
  9.     }  
  10. }  
protected void Page_Load(object sender, EventArgs e)
{
    Func<string, string> convertMeth = str => str.ToUpper();        
    string[] words = { "orange", "apple", "Article", "elephant" };        
    IEnumerable<String> aWords = words.Select(convertMeth);
    foreach (String s in aWords)
    {
       Response.Write(s + "<br/>");
    }
}


 

Func<T1, T2, TResult> 委托

封装一个具有两个参数并返回 TResult 参数指定的类型值的方法。 

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1,T2 arg2) 

 

注意:Func的重载都是需要有返回值的,但是如果我的方法不需要返回值呢?那就應該是使用Action

 

Predicate 泛型委托

“Predicate 泛型委托”表示定义一组条件并确定指定对象是否符合这些条件的方法,其本质为一委托,在该委托中定义一组条件,用以判断传入对象是否符合这些条件,如果符合,返回True,如果不符合,返回false。


Predicate<T> 委托

表示定义一组条件并确定指定对象是否符合这些条件的方法。

public delegate bool Predicate<T>( T obj)
类型参数说明:
  • T:要比较的对象的类型。
  • obj:要按照由此委托表示的方法中定义的条件进行比较的对象。
  • 返回值:如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。
  此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素:
  Array : public T[] FindAll<T>(T[] array, Predicate<T> match);
  List:public List<T> FindAll(Predicate<T> match);
下面给出两个例子,第一个例子演示“Predicate 泛型委托”在Array、List集合中的应用,第二个例子演示“Predicate 泛型委托”的拓展应用。
 
  1. public class GenericDelegateDemo   
  2. {   
  3.     List<String> listString = new List<String>()   
  4.     {   
  5.         "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"  
  6.     };   
  7.    
  8.     String[] arrayString = new String[]    
  9.     {   
  10.          "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"  
  11.     };   
  12.    
  13.     public String[] GetFirstStringFromArray()   
  14.     {   
  15.         return Array.FindAll(arrayString, (c) => { return c.Length <= 3; });   
  16.     }   
  17.    
  18.     public List<String> GetFirstStringFromList()   
  19.     {   
  20.         return listString.FindAll((c) => { return c.Length <= 3; });   
  21.     }   
  22.    
  23.     public String[] GetFirstStringFromArray_1()   
  24.     {   
  25.         return Array.FindAll(arrayString, GetString);   
  26.     }   
  27.    
  28.     public List<String> GetFirstStringFromList_1()   
  29.     {   
  30.         return listString.FindAll(GetString);   
  31.     }   
  32.    
  33.     private bool GetString(String str)   
  34.     {   
  35.         if (str.Length <= 3)   
  36.             return true;   
  37.         else  
  38.             return false;   
  39.     }   
  40. }   
public class GenericDelegateDemo 
{ 
    List<String> listString = new List<String>() 
    { 
        "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
    }; 
 
    String[] arrayString = new String[]  
    { 
         "One","Two","Three","Four","Fice","Six","Seven","Eight","Nine","Ten"
    }; 
 
    public String[] GetFirstStringFromArray() 
    { 
        return Array.FindAll(arrayString, (c) => { return c.Length <= 3; }); 
    } 
 
    public List<String> GetFirstStringFromList() 
    { 
        return listString.FindAll((c) => { return c.Length <= 3; }); 
    } 
 
    public String[] GetFirstStringFromArray_1() 
    { 
        return Array.FindAll(arrayString, GetString); 
    } 
 
    public List<String> GetFirstStringFromList_1() 
    { 
        return listString.FindAll(GetString); 
    } 
 
    private bool GetString(String str) 
    { 
        if (str.Length <= 3) 
            return true; 
        else
            return false; 
    } 
} 

(1)首先,上面以 数组和泛型List 两个集合作为演示对象,并构建集合。
(2)接着,两者同时使用各自 所有的 FindALL方法,参见如下定义:
    Array : public T[] FindAll<T>(T[] array, Predicate<T> match);
    List:public List<T> FindAll(Predicate<T> match);
    注意的是,两处的FindAll 均采用了Predicate (泛型委托)作为参数的类型。
(3)接着,使用两者方式展现 对Predicate 的使用:
    第一种:  (c) => { return c.Length <= 3; };
    第二种: GetString(String str)。
这两者在语法上明显不同,但是实际是做相同的事情,第一种是使用Lambda表达式构建的语句,关于Lambda这里不做详述,请参见笔者C#3.0特性相关文章。

补充的是你也可以这样写,

delegate(String c){return c.Length<=3;}

作为 Predicate定义的参数
完整代码:
XX.FindAll(delegate(String c) { return c.Length <=3; }); 

这应该称为匿名代理了。
其他使用到Predicate 有
  Array.Find , Array.FindAll , Array.Exists , Array.FindLast , Array.FindIndex .....
  List<T>.Find , List<T>.FindAll , List<T>.Exists , List<T>.FindLast , List<T>.FindIndex .....

例子二: 

 除了上面提到的外,你完全可以使用Predicate 定义新的方法,来加强自己代码。

  1. public class GenericDelegateDemo   
  2. {   
  3.     List<String> listString = new List<String>() { "One""Two""Three""Four""Fice""Six""Seven""Eight""Nine""Ten" };   
  4.         
  5.     public String GetStringList(Predicate<String> p)   
  6.     {   
  7.         foreach (string item in listString)   
  8.         {   
  9.             if (p(item))   
  10.                 return item;   
  11.         }   
  12.         return null;   
  13.     }   
  14.    
  15.     public bool ExistString()   
  16.     {   
  17.         string str = GetStringList(a => { return a.Length <= 3 && a.Contains('S'); });   
  18.         if (str == null)   
  19.             return false;   
  20.         else  
  21.             return true;   
  22.     }   
  23. }   
public class GenericDelegateDemo 
{ 
    List<String> listString = new List<String>() { "One", "Two", "Three", "Four", "Fice", "Six", "Seven", "Eight", "Nine", "Ten" }; 
      
    public String GetStringList(Predicate<String> p) 
    { 
        foreach (string item in listString) 
        { 
            if (p(item)) 
                return item; 
        } 
        return null; 
    } 
 
    public bool ExistString() 
    { 
        string str = GetStringList(a => { return a.Length <= 3 && a.Contains('S'); }); 
        if (str == null) 
            return false; 
        else
            return true; 
    } 
} 

Converter 泛型委托
  摘要:  表示将对象从一种类型转换为另一种类型的方法。
     参数:input:  要转换的对象。
     类型参数:  TInput:  要转换的对象的类型。TOutput: 要将输入对象转换到的类型。
    返回结果:  TOutput,它表示已转换的 TInput。
  1. public delegate TOutput Converter<in TInput, out TOutput>(TInput input);  
  public delegate TOutput Converter<in TInput, out TOutput>(TInput input);

Converter泛型委托可以说是Func泛型委托中的一个实例
 
posted @ 2012-12-20 15:24  小杜或者阿杜  阅读(157)  评论(0)    收藏  举报