C# 有返回类型的内置委托—Func
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时的使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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后的使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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(); } }
当然,我们还可以借助匿名方法更加便捷地使用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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