2.1 初識Func
MSDN給出的定義: 封裝一個具有一個參數並返回 TResult 參數指定的類型值的方法。
此委托的定義如下:
public delegate TResult Func<in T, out TResult>(T arg)
(1)in T :此委托封裝的方法的參數類型。
(2)out TResult :此委托封裝的方法的返回值類型。
可以使用此委托表示一種能以參數形式傳遞的方法,而不用顯式聲明自定義委托。封裝的方法必須與此委托定義的方法簽名相對應。也就是說,封裝的方法必須具有一個通過值傳遞給它的參數,並且必須返回值。
2.1.1 沒有Func時的使用

delegate string ConvertMethod(string inString); public class DelegateExample { public static void Main() { ConvertMethod convertMeth = UppercaseString; string name = "Dakota"; Console.WriteLine(convertMeth(name)); } private static string UppercaseString(string inputString) { return inputString.ToUpper(); } }
2.1.2 有了Func后的使用

public class GenericFunc { public static void Main() { Func<string, string> convertMethod = UppercaseString; string name = "Dakota"; Console.WriteLine(convertMethod(name)); } private static string UppercaseString(string inputString) { return inputString.ToUpper(); } }
當然,我們還可以借助匿名方法更加便捷地使用:

public class Anonymous { public static void Main() { Func<string, string> convert = delegate(string s) { return s.ToUpper();}; string name = "Dakota"; Console.WriteLine(convert(name)); } }
可以清楚地看出,現在使用 Func 委托時,不必顯式定義一個新委托並將命名方法分配給該委托。
2.2 深入Func
2.2.1 用法先行:爽一下
我們已經知道Func委托是帶指定返回值類型的委托,那么我們來看看在實際開發場景的一幕。還是以剛剛那個數據集合PersonList為例,在很多時候我們需要對從數據庫中讀取的數據集合進行二次篩選,這時我們可以使用List集合的Select方法,我們將一個Func委托實例作為方法參數傳遞給Select方法,就可以返回一個符合我們指定條件的新數據集合。
(1)先來看看Select方法的定義:
// // 摘要: // 將序列中的每個元素投影到新表中。 // // 參數: // source: // 一個值序列,要對該序列調用轉換函數。 // // selector: // 應用於每個元素的轉換函數。 // // 類型參數: // TSource: // source 中的元素的類型。 // // TResult: // selector 返回的值的類型。 // // 返回結果: // 一個 System.Collections.Generic.IEnumerable<T>,其元素為對 source 的每個元素調用轉換函數的結果。 // // 異常: // System.ArgumentNullException: // source 或 selector 為 null。 public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);
可以看出,Select方法中的參數采用了Func泛型委托,根據泛型委托的定義TSource和TResult分別代表要傳入的數據類型以及要返回的數據類型。
(2)再來看看如何在程序中使用Func委托:
首先定義一個與源數據類型不同的新數據類型作為返回值類型:
public class LitePerson { public string Name { get; set; } }
①標准定義版:
List<Person> personList = GetPersonList(); IEnumerable<LitePerson> litePersonList = personList.Select<Person, LitePerson>( new Func<Person, LitePerson> ( delegate(Person p) { return new LitePerson() { Name = p.Name }; } ) );
②嘻哈簡化版:借助編譯器提供的自動識別,簡化我們的代碼
IEnumerable<LitePerson> litePersonList = personList.Select( delegate(Person p) { return new LitePerson() { Name = p.Name }; } );
③絕逼懶人版:借助匿名類和泛型可以大大簡化我們的代碼
var liteList = personList.Select(delegate(Person p) { return new { Name = p.Name, AddDate = DateTime.Now }; });
(3)調試運行可以得到以下結果:
2.2.2 原理為王:探一次
(1)通過Reflector反編譯,我們再來看看編譯器幫我們生成的東東:
(2)看看自動生成的委托和方法的定義:
相信經過上節Action的詳細分析,這里大家應該也可以舉一反三了解編譯器幫我們到底做了什么事兒了,這里我就不再贅述了,后面也不會再贅述此方面的東東(為了節省頁面大小)。
當然,和Action類似,.NET基類庫為我們也提供了多達16個輸入參數的Func委托,但是,輸出參數卻只有1個。
出處:http://edisonchou.cnblogs.com