本文以实例形式讲解了C#的匿名方法的用法,分享给大家供大家参考之用。具体如下:
匿名方法是C# 2.0的语言新特性。首先看个最简单的例子:
class Program { static void Main(string[] args) { List<string> names = new List<string>(); names.Add("Sunny Chen"); names.Add("Kitty Wang"); names.Add("Sunny Crystal"); List<string> found = names.FindAll( new Predicate<string>(NameMatches)); if (found != null) { foreach (string str in found) Console.WriteLine(str); } } static bool NameMatches(string name) { return name.StartsWith("sunny", StringComparison.OrdinalIgnoreCase); } }
这段代码在开始的时候初始化了一个字符串列表(string list),然后通过列表的FindAll方法来查找以“sunny”起始的字符串,最后将所查找到的所有结果输出。
我们需要着重介绍List<T>的FindAll方法。这个方法是一个参数为Predicate<T>类型、返回值为List<T>类型的函数。注意,Predicate<T>是一个泛型委托,它指代这样一些函数:这些函数仅有一个T类型的参数,并且返回值是布尔类型。通过reflector等工具,我们可以看到Predicate<T>的定义如下:
public delegate bool Predicate<T>(T obj);
至此我们也多少能够猜到FindAll方法的具体实现。即针对List<T>中的每个元素,调用Predicate<T>所指代的函数,如果函数返回为true,则将其加入新建的列表中。遍历完所有的元素后,将新建的列表返回给调用者。如下:
public List<T> FindAll<T>(Predicate<T> match) { List<T> ret = new List<T>(); foreach (T elem in items) { if (match(elem)) ret.Add(elem); } return ret; }
因此,针对上面的例子,要调用FindAll方法,我们必须先定义一个参数为string类型,返回值为布尔类型的函数,在这个函数中,对参数进行条件判断,如果符合条件(也就是以“sunny”作为起始字符串),那么就返回true,否则返回false。最后再将这个函数作为参数传递给FindAll。于是也就得到了最上面的代码。
在上面的例子中,为了调用FindAll方法,我们不得不新定义一个函数,其实这个函数除了FindAll方法要用外,别的地方都几乎很少使用到它,你还不得不给它起个名字。如果程序中有多处需要调用FindAll方法,或者类似的情况,那么整个程序也就会出现一大批“只有一个地方使用”的函数,使得代码难于阅读和维护。
由于存在这样的问题,C# 2.0引入了匿名方法。开发人员在实现方法的时候,只需要给出方法的参数列表(甚至也可以不给)以及方法具体实现,而不需要关心方法的返回值,更不必给方法起名字。最关键的是,只在需要的地方定义匿名方法,保证了代码的简洁。
匿名方法只在需要的地方定义,定义的时候,使用delegate关键字,后接参数列表,然后跟上用一对花括号包括起来的函数体即可。上面的代码可以重构成下面的形式:
class Program { static void Main(string[] args) { List<string> names = new List<string>(); names.Add("Sunny Chen"); names.Add("Kitty Wang"); names.Add("Sunny Crystal"); List<string> found = names.FindAll( delegate(string name) { return name.StartsWith("sunny", StringComparison.OrdinalIgnoreCase); }); if (found != null) { foreach (string str in found) Console.WriteLine(str); } } //static bool NameMatches(string name) //{ // return name.StartsWith("sunny", // StringComparison.OrdinalIgnoreCase); //} }
此时,我们完全不需要NameMatches方法了,直接将匿名方法作为参数传递给FindAll方法。其实匿名方法本身还是有名字的,只是我们并不关心它究竟该取什么名字,因而.NET帮我们随便取了个名字罢了。
匿名方法在C#中应用十分广泛,因为委托作为函数参数是件非常平常的事情。在定义简单的事件处理过程时,我们同样可以使用匿名方法。比如:
ServiceHost host = new ServiceHost(typeof(FileTransferImpl)); host.Opened += delegate(object sender, EventArgs e) { Console.WriteLine("Service Opened."); };
匿名方法可以很方便地使用本地变量,这与单独定义的命名方法相比,能够简化编程。比如上文的例子中,假如Main函数里面定义了一个整型本地变量(局部变量)number,那么可以在delegate (string name)这一匿名方法定义中使用number变量。
上文提到,在定义匿名方法的时候,连参数列表都可以省略。因为编译器可以根据委托的签名来确定函数的签名,然后只要再给函数起个名字就可以了。下面的代码演示了这种使用方式:
delegate void IntDelegate(int x); // 带参数的定义方式 IntDelegate d2 = delegate(int p) { Console.WriteLine(p); }; // 不带参数的定义方式(当然也没带返回值) IntDelegate d3 = delegate { Console.WriteLine("Hello."); };
在使用不带参数和返回值的匿名方法定义时,需要注意以下两点:
1.如果在你的匿名方法中需要对参数进行处理,那么你不能使用不定义参数列表的声明方式。也就是在定义匿名方法的时候,需要给出参数列表。
2.不带参数和返回值的匿名方法,可以被具有任何形式签名的委托所指代。
上述第一点显而易见,因为你没有定义参数列表,也就没有办法使用参数;要说明第二点,我们可以看下面的代码:
class Program { delegate void IntDelegate(int x); delegate void StringDelegate(string y); static void Output(IntDelegate id) { } static void Output(StringDelegate sd) { } static void Main(string[] args) { /* * ERROR: The call is ambiguous between * Output(IntDelegate) * and * Output(StringDelegate) */ Output(delegate { }); } }
上面的代码没法编译通过,因为编译器不知道应该将delegate { }这一匿名方法还原为由IntDelegate指代的函数,还是还原为由StringDelegate指代的函数。此时只能显式给定参数列表,以便让编译器知道,我们究竟是想调用哪个Output函数。
希望本文所述对大家的C#程序设计有所帮助
本文向大家介绍C#基础之委托用法实例教程,包括了C#基础之委托用法实例教程的使用技巧和注意事项,需要的朋友参考一下 本文以实例形式简单介绍了C#中委托的用法,是深入学习C#程序设计所必须掌握的重要技巧。现以教程形式分享给大家供大家参考之用。具体如下: 首先,委托是C#中最为常见的内容。与类、枚举、结构、接口一样,委托也是一种类型。类是对象的抽象,而委托则可以看成是函数的抽象。一个委托代表了具有相同
本文向大家介绍C#基础之Lambda表达式用法实例教程,包括了C#基础之Lambda表达式用法实例教程的使用技巧和注意事项,需要的朋友参考一下 本文以实例形式介绍了C#中Lambda表达式的用法,分享给大家供大家参考之用。具体如下: 从委托的角度来看,Lambda表达式与匿名方法没有区别。在前面C#基础之匿名方法一文中,我们使用了匿名方法来调用List<T>的FindAll方法。从C# 3.0开始
本文向大家介绍C#基础之泛型委托实例教程,包括了C#基础之泛型委托实例教程的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#中泛型委托的用法,并以示例形式较为详细的进行了用法分析。分享给大家供大家参考之用。具体如下: 首先,泛型委托是委托的一种特殊形式,虽然感觉看上去比较怪异,其实在使用的时候跟委托差不多,不过泛型委托更具有类型通用性。 就拿C#里最常见的委托EventHandler打比
本文向大家介绍C#基础之异步调用实例教程,包括了C#基础之异步调用实例教程的使用技巧和注意事项,需要的朋友参考一下 本文实例形式展示了C#中异步调用的实现方法,并对其原理进行了较为深入的分析,现以教程的方式分享给大家供大家参考之用。具体如下: 首先我们来看一个简单的例子: 小明在烧水,等水烧开以后,将开水灌入热水瓶,然后开始整理家务 小文在烧水,在烧水的过程中整理家务,等水烧开以后,放下手中的家务
本文向大家介绍WinForm之BindingSource基础操作实例教程,包括了WinForm之BindingSource基础操作实例教程的使用技巧和注意事项,需要的朋友参考一下 通常我们在进行数据绑定的时候,常用的数据源有DataSet、DataTable、BindingList<T>、还有强类型数据源。今天我们来通过实例了解一下BindingSource组建,分享给大家供大家参考借鉴之用。 B
C++是C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。 C++不仅拥有计算机高效运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。