委托学习过程及委托、Lambda表达式和匿名方法的关系总结及事件总结
第一章,当开始学习委托的时候,我们会问什么是委托?为什么要学习委托?
一,什么是委托?
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
(一个委托是一个指向一个方法的引用,或者说,一个委托的实例就是一个指向某个方法的对象)。
二,为什么要学习委托?
1,通常情况下:当项目中所需的功能(需求)越多,则相应需要的方法也就越多,一般做法是每个功能(需求)单独学方法,但是这样会造成代码冗余。
例如:三个需求
//1、将一个字符串数组中每个元素都转换成大写
//2、将一个字符串数组中每个元素都转换成小写
//3、将一个字符串数组中每个元素两边都加上 双引号
class Program
{
static void Main(string[] args)
{
//三个需求
//1、将一个字符串数组中每个元素都转换成大写
//2、将一个字符串数组中每个元素都转换成小写
//3、将一个字符串数组中每个元素两边都加上 双引号
string[] words = { "abCDefG", "HIJKlmnOP", "QRsTuvW", "XyZ" };
////////////////普通方法调用函数////////
ProStToUpper(words);
ProStrToLower(words);
ProStrSYH(words); }
//三个具体的方法 的定义
public static void ProStToUpper(string[] word)
{
for (int i = ; i < word.Length; i++)
{
word[i] = word[i].ToUpper();
}
}
public static void ProStrToLower(string[] word)
{
for (int i = ; i < word.Length; i++)
{
word[i] = word[i].ToLower();
}
}
public static void ProStrSYH(string[] word)
{
for (int i = ; i < word.Length; i++)
{
word[i] = "\"" + word[i] + "\"";
}
} }
2,有没有一种好的方法可以将代码中的一些方法提出来并将方法作为参数当需要时作为参数传递实现功能,即将方法作为参数???? 因此需要某种类型的形参来接受作为参数的方法的传递,即有一个参数可以接受传递的方法参数。??? 这种类型为委托类型,传递的方法为委托方法。
public delegate string DelProStr(string words); //////////////////////////////////////////////(1)声明委托 (在类的外部声明 返回值类型+参数类型及个数)
class Program
{
static void Main(string[] args)
{
//三个需求
//1、将一个字符串数组中每个元素都转换成大写
//2、将一个字符串数组中每个元素都转换成小写
//3、将一个字符串数组中每个元素两边都加上 双引号
string[] words = { "abCDefG", "HIJKlmnOP", "QRsTuvW", "XyZ" }; //1. ProStr(words, StrToUpper); //2. ProStr(words, StrToLower);
//
ProStr(words, StrSYH);//传参 方法(StrSYH)作为参数 (3)将委托与具体方法绑定
for (int i = ; i < words.Length; i++)
{
Console.WriteLine(words[i]);
}
Console.ReadKey();
} public static void ProStr(string[] word, DelProStr del)
//传参时 DelProStr del=StrToUpper或(StrToLower)或(StrSYH):《=》 DelProStr del= new DelProStr(具体方法);委托所指向的函数必须跟委托具有相同的签名:相同的返回值类型+参数类型及个数
{
for (int i = ; i < word.Length; i++)
{
word[i] = del(word[i]); ///////////////(4)委托调用
}
}
/////////////////////////////////////////////////////////////////////////////////////////(2)根据委托定义具体方法/////////
public static string StrToUpper(string word)//具体方法1
{
return word.ToUpper();
}
public static string StrToLower(string word)//具体方法2
{
return word.ToLower();
} public static string StrSYH(string word)//具体方法3
{
return "\"" + word+ "\"";
} }
从上面可以看出其实,代码还是不少,继续改进为: (使用匿名函数) 方法只执行一次是时考虑使用 (匿名函数当做参数传递)
public delegate string DelProStr(string word); //DelProStr 委托名称
class Program
{
static void Main(string[] args)
{
//三个需求
//1、将一个字符串数组中每个元素都转换成大写
//2、将一个字符串数组中每个元素都转换成小写
//3、将一个字符串数组中每个元素两边都加上 双引号
string[] words = { "abCDefG", "HIJKlmnOP", "QRsTuvW", "XyZ" }; ProStr(words, delegate (string word)
{
// return "\"" + word + "\"";
//return word.ToUpper();//大写
return word.ToLower();//小写
});
for (int i = ; i < words.Length; i++)
{
Console.WriteLine(words[i]);
}
Console.ReadKey();
} public static void ProStr(string[] word, DelProStr del)//del 委托变量
{
for (int i = ; i < word.Length; i++)
{
word[i] = del(word[i]);//委托调用
}
} }
现在我们可能会产生一种疑问匿名函数是啥?该咋用?
1.匿名函数概念?
简而言之,匿名函数就是没有函数名称的函数(方法)。
2.该咋用?
A,B函数需要在满足某种特定条件下才去执行,因此我们不必要去为功能单独添加函数A,B,我们可以使用匿名函数来直接实现 。
使用格式: 委托变量=delegate(参数){需要执行的A,B方法体} 参数:是根据委托创建的具体方法需要的参数类型
还有一种与匿名函数相似的方法,但是比匿名函数高级的写法为lambda表达式 :没有函数名称与delegate的函数
public delegate string DelProStr(string word);
class Program
{
static void Main(string[] args)
{
//三个需求
//1、将一个字符串数组中每个元素都转换成大写
//2、将一个字符串数组中每个元素都转换成小写
//3、将一个字符串数组中每个元素两边都加上 双引号
string[] words = { "abCDefG", "HIJKlmnOP", "QRsTuvW", "XyZ" }; ProStr(words, (string word)=>
{
return word.ToLower();//小写
});//使用lambda表达式的写法
for (int i = ; i < words.Length; i++)
{
Console.WriteLine(words[i]);
}
Console.ReadKey();
} public static void ProStr(string[] word, DelProStr del)
{
for (int i = ; i < word.Length; i++)
{
word[i] = del(word[i]);
}
} }
“Lambda 表达式”是一个匿名函数,
所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。Lambda 表达式 x => x * x 读作“x goes to x times x”。 第二章,通过另外的例子总结委托、Lambda表达式和匿名方法的关系。
1.委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的调用可以像其他任何方法一样,具有参数和返回值
2.C# 2.0 版引入了 匿名方法的概念,此类方法允许将代码块作为参数传递,以代替单独定义的方法。C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。
匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。这些功能统称为匿名函数。
“匿名方法”就是没有名称的方法。匿名方法通常用于将代码块作为委托参数进行传递。
3.“Lambda 表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。
所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。该 Lambda 运算符的左边是输入参数(如果有),
右边包含表达式或语句块。Lambda 表达式 x => x * x 读作“x goes to x times x”。 例如:使用三种方式实现两个数的相加。
delegate int AddDelegate(int a, int b);//委托类
class AddClass
{
int a;
int b;
public AddClass(int a, int b)//构造函数
{
this.a = a;
this.b = b;
}
///////////////////////////////////三个具体的方法
private int Add1(int a, int b)
{
return a + b;
} public int Add2()
{
AddDelegate myAdd = new AddDelegate(Add1);//使用new 关键字创建对象必须要先有方法与之绑定
//<=> AddDelegate myAdd=Add1 return myAdd(a, b);
} public int Addition3()
{
AddDelegate myAdd = delegate(int a, int b) { return a + b; }; //匿名方法 return myAdd(a, b);
}
public int Addition3()
{
AddDelegate myAdd = (a, b) => a + b; //Lambda表达式 return myAdd(a, b);
}
}
特例:
(1)Func委托 是系统已经定义好的委托 0~16个参数,有返回值
(1.1)无参数带返回值 Func<T> fun=()=>{方法体带返回值}
(1.2)有参数带返回值 Func<T,TResult> fun=()=>{方法体带返回值} TResult为方法的返回类型。
Func委托有5个重载形式,区别仅在于它所指向的方法的签名的参数个数,分别如下: Func<TResult> Func<T,TResult> Func<T1,T2,TResult> unc<T1,T2,T3,TResult> Func<T1,T2,T3,T4,TResult>
其中T,T1,..T4是委托指向的方法的参数的类型,TResult为方法的返回类型。
如何使用Func委托?
首先,需要一个具体的方法。
其次,使用Func委托定义变量并关联方法
最后,委托调用
(2)Action委托 是系统已经定义好的委托 0~16个参数,无返回值
(2.1)Action action=(参数可选)=>{方法体中无返回值}
(2.2)Action<T> act=(参数可选)=>{方法体中无返回值}
Action委托也有16个重载形式,分别如下:
Action Action<T> Action<T1,T2> Action<T1,T2,T3>
..
Action<T1,T2,T3,T4..>
其中T,T1,..T4...是委托指向的方法的参数的类型。
从上面的委托形式我们就可以分析出来,Func和Action委托的唯一区别在于Func要有返回值, Action没有返回值。
第三章: 事件
1.事件的由来:
实际应用中,通常都是 Program在一个类中,三个具体方法在另外的类中。但并不是所有的字段都应该声明成public,合适的做法是应该public的时候public,应该private的时候private。对于委托对象有些时候需要public有些时候需要private。当把委托对象(DelProStr)声明为private时,会怎么样呢???有点小无语。因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见,那它还有什么用?
再看看把委托对象(DelProStr)声明为 public 会怎样?结果就是:在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性。
现在我们想想,如果DelProStr不是一个委托类型,而是一个string类型,你会怎么做?答案是使用属性对字段进行封装。于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
2.什么是事件?
事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。
public DelProStr delProStr;//delProStr这是一个委托变量
public event DelProStr eventDelProStr;//eventDelProStr 事件:委托变量关键字+event
委托:是一种类型 (形如Person类)
事件:是委托的一个实例 (形如 由Person类实例化后的对象变量man) Person man=new Person();
3.怎么使用事件??
前提是要声明一个委托
首先,声明一个事件(在委托的基础上才能实现) :实为对委托的封装
然后判断eventDelProStr是否为空 :只有在(动作)事件注册后并判断是否有事件然后才能执行。
if(eventDelProStr!=null)
{
eventDelProStr.Invoke();//执行注册的(动作) 而不是方法
}
最后,(外界)注册(动作)事件 (通过“+=”和 “-+”) (跟委托与方法关联的步骤一样)
委托与事件的区别:
(1)事件不允许外面直接对事件赋值方法 委托在外界赋值后会导致赋值之前的注册会失效
(2)事件不允许在外面直接调用事件 委托在外界调用会跳过委托方法(会重置关联的方法使之变为null)
学习地址:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx (C# 中的委托和事件)
委托学习过程及委托、Lambda表达式和匿名方法的关系总结及事件总结的更多相关文章
- Lambda表达式与匿名方法
在C#2中,由于有了方法组,匿名方法,类型的协变和抗变,使得运用delegate变得很容易,在注册事件时代码变得简单易读,但是在C# 2中,代码仍然有点臃肿,大块的匿名方法会降低代码的可读性,一般我们 ...
- 匿名函数:Lambda表达式和匿名方法
匿名函数一个"内联"语句或表达式,可在需要委托类型的任何地方使用.可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数: Lamb ...
- Effective Java 第三版——42.lambda表达式优于匿名类
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- kotlin之lambda表达式和匿名函数
lambda表达式,称为匿名函数,是一种函数字面值,也就是没有声明的函数,但可以作为表达式传递出去. 函数类型: 对于接受另一个函数的作为自己的参数,必须针对这个参数指定一个函数的类型如 fun &l ...
- Python函数与lambda 表达式(匿名函数)
Python函数 一.函数的作用 函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段 函数能提高应用的模块性和代码的重复利用率 python 内置函数:https://docs.pytho ...
- Lambda 表达式-即匿名函数
拉姆达值(Lambda),希腊字母表示为Λ,指与真空的空间有关的能量或暗能量. 代表转换的常量.或者转换本身. Lambda 表达式 Lambda 表达式”是一个匿名函数,可以包含表达式和语句 ...
- C++11 Lambda表达式(匿名函数)
http://www.cnblogs.com/RainyBear/p/5733399.html http://blog.163.com/lvan100@yeah/blog/static/6811721 ...
- lambda表达式、匿名函数
lambda表达式是函数式编程中的匿名函数语法规范. In computer programming, an anonymous function (function literal, lambda ...
- C++11 — lambda表达式(匿名函数)
C++11中lambda表达式的基本语法格式为: [capture](parameters) -> return_type { /* ... */ } 其中 [] 内为外部变量的传递方式: [] ...
随机推荐
- python3获取当前目录和上级目录
d = path.dirname(__file__) #返回当前文件所在的目录 # __file__ 为当前文件 获得某个路径的父级目录: parent_path = os.path.dirname( ...
- 基于点线特征的Kinect2实时环境重建(Tracking and Mapping)
前言 个人理解错误的地方还请不吝赐教,转载请标明出处,内容如有改动更新,请看原博:http://www.cnblogs.com/hitcm/ 如有任何问题,feel free to contact m ...
- hasura graphql-engine v1.0.0-alpha26 版本新功能
hasura 发布了graphql-engine v1.0.0-alpha26 版本,有一些破坏的变动,以及方便的新特性 破坏性变动 order_by 从 order_by: id_asc 为 ord ...
- stenciljs 学习六 组件开发样式指南
组件不是动作,最好使用名词而不是动词, 文件结构 每个文件一个组件. 每个目录一个组件.虽然将类似的组件分组到同一目录中可能是有意义的,但我们发现当每个组件都有自己的目录时,更容易记录组件. 实现(. ...
- jquery 1.9里面已经删除了toggle(fn1, fn2)函数:
jquery 1.9里面已经删除了toggle(fn1, fn2)函数:引用Note: This method signature was deprecated in jQuery 1.8 and r ...
- 未能正确加载“VSTS for Database Professionals Sql Server Data-tier Application”包。(转)
今天费了九牛二虎之力,重转好了vs2010之后,打开解决方案,报出下面的错误: ---------------------------Microsoft Visual Studio---------- ...
- hdu 6305 RMQ Similar Sequence——概率方面的思路+笛卡尔树
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6305 看题解,得知: 0~1内随机取实数,取到两个相同的数的概率是0,所以认为 b 序列是一个排列. 两个 ...
- JSP 执行流程
一.jsp执行流程 1. 发送请求 ,请求访问jsp文件. 2. 服务器(Tomcat)提供的jsp parser 解析器解将jsp转化为java文件. jsp本质上是一个servlet. 3.ser ...
- JZ2440 裸机驱动 第7章 内存管理单元MMU
本章目标: 了解虚拟地址和物理地址的关系: 掌握如何通过设置MMU来控制虚拟地址到物理地址的转化: 了解MMU的内存访问权限机制: 了解TLB.Cache.Write ...
- 【linux】crontab命令
一.crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动cro ...