网站怎么做登录,课程网站开发背景,合网站 - 百度,网站建设策划报告转载自诗人江湖老,原文地址 匿名函数#xff08;Anonymous Function#xff09;是表示“内联”方法定义的表达式。匿名函数本身及其内部没有值或者类型#xff0c;但是可以转换为兼容的委托或者表达式树类型(了解详情)。匿名函数转换的计算取决于转换的目标类型#xff1a;…转载自诗人江湖老,原文地址 匿名函数Anonymous Function是表示“内联”方法定义的表达式。匿名函数本身及其内部没有值或者类型但是可以转换为兼容的委托或者表达式树类型(了解详情)。匿名函数转换的计算取决于转换的目标类型如果是委托类型则转换计算为引用匿名函数所定义的方法的委托如果是表达式树类型则转换将计算以对象结构形式表示方法结构的表达式树。 匿名函数有两种语法风格Lambda表达式(lambda-expression)和匿名方法表达式(anonymous-method-expression)。在几乎所有的情况下Lambda表达式都比匿名方法表达式更为简介具有表现力。但现在C#语言中仍保留了后者为了向后兼容。 Lambda表达式 async可选 (匿名的函数签名) (匿名的函数体) 匿名方法表达式 async可选 delegate (显式的匿名函数签名) 可选{代码块} 其中匿名的函数签名可以包括两种一种是隐式的匿名函数签名另一种是显式的匿名函数签名 隐式的函数签名(p)、(p1,p1) 显式的函数签名(int p)、(int p1,int p2)、(ref int p1,out int p2) 匿名的函数体可以是表达式或者代码块。 从上面我们可以看出Lambda表达式的参数形式可以显式或者隐式类型化。在显式类型化参数列表中每个参数的类型是显式声明的在隐式类型化参数列表中参数的类型是从匿名函数出现的上下文中推断出来的。 当Lambda表达式只有一个具有隐式类型化参数的时候参数列表可以省略圆括号也就是说 (参数) 表达式 可以简写为 参数 表达式
一些匿名函数的示例 x x 1 //隐式的类型化函数体为表达式 x {return x 1;} //隐式的类型化函数体为代码块 (int x) x 1 //显式的类型化函数体为表达式 (int x) {return x 1;} //显式的类型化函数体为代码块 (x , y) x * y //多参数 () Console.WriteLine() //无参数 async (t1 , t2) await t1 await t2 //异步 delegate (int x) {return x 1;} //匿名函数方法表达式 delegate {return 1 1;} //参数列表省略 Lambda表达式和匿名方法表达式的区别 ● 当没有参数的时候匿名方法表达式允许完全省略参数列表从而可以转换为具有任意值参数列表的委托类型Lambda表达式则不能省略参数列表的圆括号()。 ● Lambda表达式允许省略和推断类型参数而匿名方法表达式要求显式声明参数类型。 ● Lambda表达式主体可以为表达式或者代码块而匿名方法表达式的主体必须为代码块。 ● 只有Lambda表达式可以兼容到表达式树类型。
委托 一个委托是一个指向一个方法的引用或者说一个委托的实例就是一个指向某个方法的对象这是一个简单却十分强大的概念。 C#中的委托是用来处理在其他语言中(如C、Pascal等)需要用函数指针来处理的情况。不过与C不同的是委托是完全面向对象的C指针仅仅指向成员函数而委托同时封装了对象的实例和方法委托是完全类型安全的只有当函数的签名与委托的签名匹配的时候委托才可以指向该方法当委托没有合法的指向方法的时候不能被调用。 一些关于委托的知识点 1.委托是类型安全的 委托类型的返回类型必须为void或者输出安全委托类型的所有形参类型都必须是输入安全的。 2.委托类型是名称等效不是结构等效 也就是说对于两个委托类型即使它们具有相同的参数列表和返回类型它们仍将被视为两个不同的委托类型。 例如 delegate int A(int x); delegate int B(int x); A和B是两个不同的委托。 但是两个结构一样的委托它们的实例可以指向同一个方法。 3.委托的调用列表(多播委托) 委托实例所封装的方法集合称为调用列表。 当我们从某个方法创建一个委托实例的时候该实例将封装此方法该实例中的调用列表包含一个“入口点”。当我们组合多个非空的委托实例的时候它们的调用列表将连接在一起形成一个新的调用列表新的调用列表中包含了多个“入口点”。 委托的组合是使用二元运算符 和 来进行的同样可以使用 - 和 - 来进行组合的移除。 下面的示例演示多个委托的实例化及其相应的调用列表
delegate void D(int x)
class
{public static void M1(int i){...}public static void M2(int i){...}
}
class Test
{static void Main(){D cd1 new D(c.M1); //M1D cd2 new D(c.M2); //M2D cd3 cd1 cd2; //M1 M2D cd4 cd3 cd1; //M1 M2 M1D cd5 cd4 cd3; //M1 M2 M1 M2}
} 实例化cd1和cd2的时候它们分别封装一个方。实例化cd3的时候它调用的列表有两个方法M1和M2而且顺序与此相同。cd4的调用列表中依次包含M1、M2、M1。最后cd5的调用列表中依次包含M2、M1、M1、M2。 4.委托的调用 当调用一个委托实例的时候将按照调用列表的顺序依次调用列表中的各个方法当在调用期间发生异常调用列表中排在后面的任何方法将不会被调用。
using System;
delegate void D(int x);
class C
{public static void M1(int i){Console.WriteLine(C.M1:i);}public static void M2(int i){Console.WriteLine(C.M1:i);} public void M3(int i){Console.WriteLine(C.M2:i);}
}class Test
{static void Main(){D cd1 new D(c.M1); //M1cd1(-1); //调用cd1D cd2 new D(c.M2); //M2cd2(-2); //调用M2D cd3 cd1 cd2; //M1 M2cd3(10); //依次调用M1、M2cd3 cd1;cd3(20); //依次调用M1、M2、M1C c new C();D cd4 new D(c.M3); cd3 cd4;cd3(30); //依次调用M1、M2、M1、M3cd3 - cd1 //移除最后一个M1cd3(40); //依次调用M1、M2、M3cd3 - cd4; cd3(50); //依次调用M1、M2cd3 - cd2cd3(60); //调用M1cd3 - cd2 //这是cd3的调用列表中没有cd2了该移除不生效不报错cd3(70); //调用M1cd3 - cd1 // cd3(70); //如果调用将会报System.NullReferenceException异常}
}
Lambda表达式 自从C#3.0开始就可以使用一种新语法把实现代码赋予委托Lambda表达式。只要有委托参数类型的地方就可以使用Lambda表达式。使用匿名方法的地方可以使用Lambda表达式来代替例如
Func string,string delagate(string para)
{para Hello World!;return param;
}可以写成
Func string,string para
{para Hello World!;return para;
} Lambda表达式运算符””的左边列出了需要的参数右边定义了赋予Lambda变量的方法的代码实现。 我们注意到无论何时只要我们需要引入匿名方法我们都需要在前面加上delegate关键字而且参数列表都需要类型化。Lambda表达式提供了一种更为简洁和自然的语法而且在C#更多高级的方面中都涉及广泛。简而言之我们应该用Lambda表达式来替代匿名方法。 例如
public class Person
{string Name;int Age;
}ListPerson personList new ListPerson();personList.Find(delegate(Person p){retrun p.Age12;});
//可以写成
personList.Find(pp.Age12);添加链接描述