Func和Action系統委托


為了方便開發,.net基類庫針對在實際開發中最常用的情形提供了幾個預定義好的委托,這些預定義委托用得很廣。

 

Func,Action
的介紹及其用法

Func是一種委托,這是在3.5里面新增的,2.0里面我們使用委托是用Delegate,Func位於System.Core命名空間下,使用委托可以提升效率,例如在反射中使用就可以彌補反射所損失的性能。

Action<T>和Func<T,TResult>的功能是一樣的,只是Action<T>沒有返類型,

Func<T,T,Result>:有參數,有返回類型
Action,則既沒有返回也沒有參數,


Func<T,TResult>
的表現形式分為以下幾種:

1。Func<T,TResult>
2。Func<T,T1,TResult>
3。Func<T,T1,T2,TResult>
4。Func<T,T1,T2,T3,TResult>
5。Func<T,T1,T2,T3,T4,TResult>

分別說一下各個參數的意義,TResult表示
委托所返回值 所代表的類型, T,T1,T2,T3,T4表示委托所調用的方法的參數類型,
Func委托聲明的最后一個泛型類型參數是委托所接收方法的返回值類型,前面的泛型類型參數(如果有的話)就是委托所接收的方法的形參類型。

 


以下是使用示例:

示例一:

static long Add(int x ,int y)

{

return x + y;

}

static void Main(string[] args)

{

//以下泛型委托變量接收擁有兩個int類型參數,返回一個long數值的方法。

Func<int,int,long> func = Add;

long result = func(100,200); //result=300

}


示例二:

Func<int, bool> myFunc = null;//全部變量

myFunc = x => CheckIsInt32(x);
//給委托封裝方法的地方 使用了Lambda表達式

private bool CheckIsInt32(int pars)//被封裝的方法
{
  return pars == 5;
}

bool ok = myFunc(5);//調用委托

示例三:(將方法作為另一個方法的參數)

namespace FuncAsFuncArgu
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
Console.WriteLine(Process(Add, numbers, 0, 5));
Console.WriteLine(Process(Multiply, numbers, 1, 5));
Console.ReadKey();
}

static int Process(Func<int, int, int> op, int[] numbers, int from, int to)
{
int result = numbers[from];
for (int i = from + 1; i <= to; i++)
result = op(result, numbers[i]);
return result;
}

static int Add(int i, int j)
{
return i + j;
}

static int Multiply(int i, int j)
{
return i * j;
}
}
}







但是如果我們需要所封裝的方法不返回值,增么辦呢?就使用Action!

可以使用
Action<T1, T2, T3, T4>委托以參數形式傳遞方法,而不用顯式聲明自定義的委托。封裝的方法必須與此委托定義的方法簽名相對應。也就是說,封裝的方法必須具有四個均通過值傳遞給它的參數,並且不能返回值。(在 C# 中,該方法必須返回 void。在 Visual Basic 中,必須通過 Sub…End Sub 結構來定義它。)通常,這種方法用於執行某個操作。
使用Action 委托,接收擁有0到4個參數且返回值類型為void的方法。
使用方法和Func類似!




Action:既沒有返回,也沒有參數,使用方式如下:

Action
action = null;//定義action

action =  CheckIsVoid;//封裝方法,只需要方法的名字

action();//調用



總結:使用Func<T,TResult>和Action<T>,Action而不使用Delegate其實都是為了簡化代碼,使用更少的代碼達到相同的效果,不需要我們顯示的聲明一個委托,Func<T,TResult>的最后一個參數始終是返回類型,而
Action<T,TResult>是沒有返回類型的,而Action是沒有返回類型和參數輸入的。






Action<T>泛型委托


描述:

    封裝一個方法,該方法只采用一個參數並且不返回值.

語法:

    public delegate void Action<T>(T arg);

T:

    參數類型:此委托封裝的方法的參數類型

arg:

    參數:此委托封裝的方法的參數

備注:

    通過此委托,可以將方法當做參數進行傳遞.

其他形式:

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

例子:

  protected void Page_Load(object sender, EventArgs 
e)
{
List<int> list = new
List<int>();
list.AddRange(new int[] { 7, 6, 10, 1, 2, 3, 4, 5,
8 });

Action<int> action = new
Action<int>(AddFive);
list.ForEach(action);

//效果同
// Action<int>
action = new
Action<int>(AddFive);
// list.ForEach(action);
//list.ForEach(x
=> Response.Write((x + 5).ToString() +
"<br/>"));

//效果同
// Action<int>
action = new
Action<int>(AddFive);
// list.ForEach(action);
//list.ForEach(delegate(int
i)
//{
// HttpContext.Current.Response.Write((i +
5).ToString() + "<br/>");
//});
}

public
static void AddFive(int
i)
{
HttpContext.Current.Response.Write((i + 5).ToString() +
"<br/>");
}



  結果:

    12
    11
    15
    6
    7
    8
    9
    10
    13




Action<(Of
<(T>)> 委托 講解(MSDN)
Posted on 2009-09-30 11:09 jowo 閱讀(128) 評論(0) 編輯
收藏

說明:封裝一個方法,該方法只采用一個參數並且不返回值。

命名空間:  System
程序集:  mscorlib(在
mscorlib.dll 中)
  C#

public delegate void Action<T>(
    T
obj
)

類型參數

T

    此委托封裝的方法的參數類型。

參數

obj
    類型:T
    此委托封裝的方法的參數。

備注

可以使用此委托以參數形式傳遞方法,而不用顯式聲明自定義的委托。該方法必須與此委托定義的方法簽名相對應。也就是說,封裝的方法必須具有一個通過值傳遞給它的參數,並且不能返回值。(在
C# 中,該方法必須返回 void。在 Visual Basic 中,必須通過 Sub…End Sub 結構來定義它。)
通常,這種方法用於執行某個操作。
018hxwa8.alert_note(zh-cn,VS.90).gif說明:

若要引用具有一個參數並返回值的方法,請改用泛型
Func<(Of <(T, TResult>)>) 委托。

在使用 Action<(Of
<(T>)>) 委托時,不必顯式定義一個封裝只有一個參數的方法的委托。例如,以下代碼顯式聲明了一個名為 DisplayMessage
的委托,並將對 WriteLine 方法或 ShowWindowsMessage
方法的引用分配給其委托實例。
C#

using System;
using
System.Windows.Forms;

delegate void DisplayMessage(string
message);

public class TestCustomDelegate
{
public static void
Main()
{
DisplayMessage messageTarget;

if
(Environment.GetCommandLineArgs().Length > 1)
messageTarget =
ShowWindowsMessage;
else
messageTarget =
Console.WriteLine;

messageTarget("Hello, World!");

}

private static void ShowWindowsMessage(string message)

{
MessageBox.Show(message);

}
}




以下示例簡化了此代碼,它所用的方法是實例化 Action<(Of <(T>)>)
委托,而不是顯式定義一個新委托並將命名方法分配給該委托。

using System;
using
System.Windows.Forms;

public class TestAction1
{
public static
void Main()
{
Action<string> messageTarget;


if (Environment.GetCommandLineArgs().Length > 1)

messageTarget = ShowWindowsMessage;
else
messageTarget =
Console.WriteLine;

messageTarget("Hello, World!");

}

private static void ShowWindowsMessage(string message)

{
MessageBox.Show(message);
}
}



您也可以按照以下示例所演示的那樣在
C# 中將 Action<(Of <(T>)>) 委托與匿名方法一起使用。(有關匿名方法的簡介,請參見匿名方法(C#
編程指南)。)

using System;
using
System.Windows.Forms;

public class TestAnonMethod
{
public
static void Main()
{
Action<string> messageTarget;


if (Environment.GetCommandLineArgs().Length > 1)

messageTarget = delegate(string s) { ShowWindowsMessage(s);
};
else
messageTarget = delegate(string s) {
Console.WriteLine(s); };

messageTarget("Hello, World!");

}

private static void ShowWindowsMessage(string message)

{
MessageBox.Show(message);
}
}



您也可以按照以下示例所演示的那樣將
lambda 表達式分配給 Action<(Of <(T>)>) 委托實例。(有關 lambda 表達式的簡介,請參見 Lambda
表達式(C# 編程指南)。)

using System;
using
System.Windows.Forms;

public class TestLambdaExpression
{
   public
static void Main()
   {
      Action<string> messageTarget;


      if (Environment.GetCommandLineArgs().Length > 1)
        
messageTarget = s => ShowWindowsMessage(s);
      else
        
messageTarget = s => Console.WriteLine(s);

      messageTarget("Hello,
World!");
   }

   private static void ShowWindowsMessage(string
message)
   {
      MessageBox.Show(message);     
  
}
}

018hxwa8.alert_note(zh-cn,VS.90).gif說明:

Visual Basic 要求
lambda 表達式返回值。因此,在 Visual Basic 中無法將 Action<(Of <(T>)>) 委托與 lambda
表達式一起使用。

ForEach 和 ForEach<(Of <(T>)>) 方法都采用 Action<(Of
<(T>)>) 委托作為參數。通過使用由委托封裝的方法,可以對數組或列表中的每個元素執行操作。此示例使用 ForEach
方法提供說明。
示例

下面的示例演示如何使用 Action<(Of <(T>)>) 委托來打印
List<(Of <(T>)>) 對象的內容。在此示例中,使用 Print 方法將列表的內容顯示到控制台上。此外,C#
示例還演示如何使用匿名方法將內容顯示到控制台上。

C#
復制代碼

using System;
using
System.Collections.Generic;

class Program
{
    static void
Main()
    {
        List<String> names = new
List<String>();
        names.Add("Bruce");
        names.Add("Alfred");
        names.Add("Tim");
        names.Add("Richard");

        //
Display the contents of the list using the Print
method.
        names.ForEach(Print);

        // The following
demonstrates the anonymous method feature of C#
        // to display the
contents of the list to the console.
        names.ForEach(delegate(String
name)
        {
            Console.WriteLine(name);
        });
    }

    private
static void Print(string
s)
    {
        Console.WriteLine(s);
    }
}
/* This code will
produce output similar to the following:
* Bruce
* Alfred
* Tim
*
Richard
* Bruce
* Alfred
* Tim
* Richard

http://www.cnblogs.com/zjw2004112/archive/2009/09/30/csharp-action-t.html




不能不說的C#特性-匿名方法和Lambda表達式


在我們程序中,經常有這樣一些需求:

1.
需要一個臨時方法,這個方法只會使用一次,或者使用的很少。

2.
這個方法的方法體很短,以至於比方法聲明都短,寫起來實在沒勁(我將其稱之為“一句話方法”)。

沒辦法,這樣的方法寫起來真是吃力不討好,比如一些按鈕事件處理中,有些按鈕點擊就是彈出一個對話框,或者調用一下別的什么方法。比如下面的代碼:
this.btnRefresh.Click
+= new System.EventHandler(this.btnRefresh_Click);
private void
btnRefresh_Click(object sender, EventArgs
e)
{
    BindData();
}

這個”Refresh”按鈕就是做一下調用一下BindData()數據綁定的方法,為此我們不得不寫一個新方法。好了,C#
2.0為我們提供了匿名方法:
this.btnRefresh.Click += delegate(object sender, EventArgs e)
{ BindData();
};

沒勁的代碼沒了。想知道這種寫法的幕后黑手么?

其實編譯器還是在我們的后面干了一件齷齪的事情:它為我們產生了一個新的方法,它只是表面上為我們節省了代碼。
privatevoidb__0(object
sender, EventArgs
e)
{
    this.BindData();
}

看看這個編譯器產生的方法的名稱:

b_0,Test是這個匿名方法所放置的地方(因為這個按鈕的時間我是放在一個Test方法里的)
還有一點需要注意的是,如果這個匿名方法是在實例方法里使用,那么編譯器為我們生成的幕后方法也是實例方法,否則就是靜態方法了。

是不是覺得匿名方法這東西很不錯,減少了很多代碼阿,但是匿名方法的使用還並不人性化,什么是人性化呢?比如你可以用自然的語言將程序代碼讀出來,
這樣才算人性化了.在.net
2.0中System.Collections.Generic命名空間下List里有一些新增的方法。比如Find,如果使用匿名方法我們如何調用呢:
books.Find(delegate(Book
book){return book.Price <
50;});

代碼是很簡單,但是卻無法朗讀出來,來看看Lambda表達式的寫法:

books.Find(book=>book.Price<50);這個Lambda表達式就可以這樣閱讀出來了:給你一本書,如果它的價格小於50則返回true。

好了,那我們就走進Lambda表達式吧:

將使用了Lambda表達式的程序集反編譯后,我們發現,它實際上和匿名方法沒有什么不同。Lambda的輸入參數就對應着delegate括號里面的參數,由於Lambda表達式可以推斷參數的類型,所以這里的參數無需聲明。

Lambda操作符讀作”Goes
to”,它后面緊跟着表達式或者是語句塊(這點和匿名方法也不同,匿名方法只能使用語句塊而不能使用表達式),下面我就用實例來說明一下有那些類型的Lambda表達式:

//x的類型省略了,編譯器可以根據上下文推斷出來,后面跟着的是表達式
//x的類型省略了,編譯器可以根據上下文推斷出來,后面跟着的是表達式
x
=> x+1
deleage(int x){return x+1;}
//后面跟着的是語句塊
x=>{return
x+1;}
delegate(int x){return x+1;}
//輸入參數也可以帶類型,帶類型后別忘記小括號哦
(int x)
=> x+1
delegate(int x){return x+1;}
//也可以多個輸入參數,逗號分隔,別忘記小括號
(x,y)
=> x+y
delegate(int x,int y){return x+y;}
//無參的也行

() =>
1

delegate(){return
1;}

對於Lambda表達式來說她的用法就是如此,但是在Lambda背后卻有很多的故事和玄機。用Lambda表達式可以構建表達式樹,而表達式樹對於Linq來說就像樹根對於樹一樣重要。在這里就不討論表達式樹的問題了,這個東西也不是三言兩語能夠說清楚的,等待時機成熟的時候我們再來進一步討論。
Lambda表達式更多閱讀

Lambda實際上源遠流長,我們現在使用的機器都是馮-諾依曼體系的,屬於圖靈機,在那之前還有一種稱作λ演算的理論,但是圖靈機由於先被實現出來,所以大行其道,λ演算后來成就了函數式編程語言特別是Lisp,在函數式編程語言里函數是第一等元素,函數的參數,函數的返回值都是函數,程序沒有變量,函數嵌套函數。而且函數式編程語言一直存在於象牙塔中,所以在工業界並沒有得到通用,不過近年來工業界比較喜歡“復古”風格,所以函數式編程語言也慢慢的走上了歷史的舞台。函數式編程能解決一些命令式編程難以解決的問題(或者解決起來非常麻煩)。C#要做到函數風格編程怎么辦?靠原來的方法定義的方式肯定是不可行的,2.0的匿名方法從某種程序上來說解決了這個問題,但還是不夠,3.0里的Lambda終於很好的解決了,一個Lambda就是一個
delegate,一個delegate指向一個方法,現在我們使用Lambda也能簡單的將方法作為參數傳遞了,還可以層層嵌套,都是很簡單的事情了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM