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<int, bool> myFunc = null;//全部變數
myFunc = x => CheckIsInt32(x);
//給委託封裝方法的地方 使用了Lambda運算式
private bool CheckIsInt32(int pars)//被封裝的方法
{
return pars == 5;
}
bool ok = myFunc(5);//調用委託
MSDN:http://msdn.microsoft.com/zh-cn/library/bb534303(VS.95).aspx
但是如果我們需要所封裝的方法不傳回值,增麼辦呢?就使用Action!
可以使用
Action<T1, T2, T3, T4>委託以參數形式傳遞方法,而不用顯式聲明自訂的委託。封裝的方法必須與此委託定義的方法簽名相對應。也就是說,封裝的方法必須具有四個均通過值傳遞給它的參數,並且不能傳回值。(在 C# 中,該方法必須返回 void。在 Visual Basic 中,必須通過 Sub…End Sub 結構來定義它。)通常,這種方法用於執行某個操作。
使用方法和Func類似!
MSDN:http://msdn.microsoft.com/zh-cn/library/bb548654(VS.95).aspx
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>)>)
委託,而不是顯式定義一個新委託並將命名方法分配給該委託。
C#
複製代碼
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#
編程指南)。)
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# 編程指南)。)
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也能簡單的將方法作為參數傳遞了,還可以層層嵌套,都是很簡單的事情了。