C#基礎-Func,Action

來源:互聯網
上載者:User
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也能簡單的將方法作為參數傳遞了,還可以層層嵌套,都是很簡單的事情了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.