委托Delegate、匿名方法和Lambda的理解和配合使用

匿名函数

匿名函数是一个“内联”语句或者表达式,可在需要委托类型的任何地方使用。可以使用匿名函数来初始化命名委托,或传递命名委托(不是命名委托类型)作为方法参数。

匿名方法

在 c#2.0引入,在这之前声明委托的唯一方法是使用命名方法。在c#3.0引入了lambda表达式取代匿名方法,作为编写内联代码的首选方式。但在一种情况下,匿名方法提供了Lambda表达式中所没有的功能,可使用匿名方法来忽略参数列表,因此匿名方法可以转换为具有各种签名的委托。

例如:

public delegate void NoReturnDelegate(object sender,EventArgs e);
public event NoReturnDelegate TestEvent;

TestEvent += delegate
{

};

TestEvent += (sender,e) =>
{

};

Lambda表达式

Lambda表达式可以包含表达式和语句,并且可用于创建委托或表达式树类型。Lambda表达式使用Lambda运算符=>,运算符左边是输入参数(如果没有输入参数或参数有两个及以上,要有括号,并且参数之间用逗号隔开),运算符右边包含表达式或语句块(如果有多条语句,要用大括号括起来,并且如果需要返回值需要显示的使用return,而对于只有一个表达式的就不需要)。

例如,分配给委托类型:

delegate int TestDelegate(int i);
TestDetegate testDetegate=x=>x+x;
分配给表达式树类型:
delegate void TestDel(int i);
Expression<TestDel> myET=x=>Console.WriteLine(x*x);
Lambda的一般规则:

Lambda包含的参数数量必须与委托类型包含的参数数量相同。

Lambda中的每个输入参数必须都能够隐式转换为其对应的委托类型。

Lambda的返回值必须能够隐式转换为委托的返回类型。

Lambda表达式中的变量范围

Lambda可以引用“外部变量”,这些变量位于在其定义Lambda的封闭方法或类型的范围内。而在Lambda表达式内定义的变量跟在方法定义的变量一样,只能内部使用。

例如:

int j=0;           Action<int> test=(int i)=>Console.WriteLine(i+j);
适用于Lambda表达式中的变量范围:
A.捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。
B.在外部方法中看不到Lambda表达式内引入的变量。
C.Lambda表达式无法从封闭方法中直接捕获ref或者out参数。
D.Lambda表达式中的返回语句不会导致封闭方法的返回。
E.Lambda表达式不能包含其目标位于所包含匿名函数主体外部或内部的goto语句、beak语句或continue语句。

委托

官方中文定义

一种定义方法签名的类型。

官方英文定义

A delegate is a type that defines a method signature。

网上查资料和自己的理解

委托看成一个特殊的类,它定义了一种方法的模型,只要与委托的签名(跟方法一样,有返回类型和参数组成)匹配的任何可以访问的类或者结构中的任何方法都可以分配给该委托,即把方法的引用分配给委托。

委托的特点

委托类似于C++函数指针,但它们是类型安全的。

委托允许将方法作为参数进行传递。

委托可用于定义回调方法。

委托可以链接在一起,例如:可以对一个事件调用多个方法。(把多个返回类型和参数都一样的方法注册到该事件中,当事件触发时按队列调用所有的方法,也可以从事件中移除某个方法)

方法不必与委托签名完全匹配。(委托的变体,多态性的体现,分为两种,一种是协变,可以返回派生自委托签名中的返回类型;另一种是逆变,可以传入派生自委托签名中的参数类型,要注意值类型不支持协变和逆变)

可以使用匿名函数(匿名方法和Lambda表达式)。

可以使用泛型作为参数和返回类型。

.net内预定义的两种委托

Action无返回并可以最多传入16参数的委托,例如:Action

Func有返回并可以最多传入16参数的委托,返回类型总是放在最后一个,例如:Func,传入一个string参数,并返回一个bool。

针对泛型类型参数,可以通过in和out来声明显式的协变和逆变

如果仅使用变体来支持匹配方法签名和委托类型,且不使用in和out关键字,则会发现,有时可以用相同的lambda表达式或方法来实例化多个委托,但无法将一个委托指派给另外一个委托。

例如:

public delegate T SmapleGenericDelegate<T>();
static void Main(string[] args)
{
SmapleGenericDelegate<string> dString = () => {
return "this type is string";
};

SmapleGenericDelegate<object> dObject = () => "this type is object";

SmapleGenericDelegate<object> multiDelegate = dString + dObject;
}

这个时候会出现错误运算符“+”无法应用于“LearningDemo.Program.SmapleGenericDelegate”和“LearningDemo.Program.SmapleGenericDelegate。

如果改成

public delegate T SmapleGenericDelegate<T>();

就不会提示错误。
原文链接: https://www.cnblogs.com/ants-guoxf/archive/2012/08/29/2661887.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/61212

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午9:53
下一篇 2023年2月9日 上午9:54

相关推荐