委托学习过程及委托、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 { /* ... */ } 其中 [] 内为外部变量的传递方式: [] ...
随机推荐
- 20155310 2016-2017-2 《Java程序设计》第八周学习总结
20155310 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章 通用API 通用API •日志:日志对信息安全意义重大,审计.取证.入侵检验等都会 ...
- JS前端数据多条件筛选(商品搜索)
有时候也会需要在前端进行数据筛选,增强交互体验.当数据可用的筛选条件较多时,把逻辑写死会给后期维护带来很大麻烦.下面是我自己写的一个简单的筛选器,筛选条件可以根据数据包含的字段动态设置. 仿照京东的筛 ...
- 将一个list转成json数组-晚上坐49路回去打卡
- Android USB gadget框架学习笔记
一 Gadget框架结构 kernel/drivers/usb/gadget,这个目录是android下usbgadget的主要目录. Gadget功能组织单元:主要文件android.c,usb g ...
- Microsoft Dynamics CRM 2013 相关安装包下载
90-day trial keys:Microsoft Dynamics CRM Workgroup Server 2013 (5 CAL limit):NX77Y-BTBCV-JP3T3-8W7JH ...
- 使用redis防止商品超发
redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用.redis中key的原子自增incrby和判断key不存在再写入的setnx方法,可以有效的防止超发. 下面使用两个不同的方 ...
- HighCharts定时刷新图表
假设图表容器的id为exChart,如下: <div style="height:450px;" id="chart"> 1. 首先在serie ...
- 【python】break和continue
break:跳出循环 ,continue:停止当前循环,进入下一次循环,但为跳出循环. passwdList=["123","456"] valid = Fal ...
- MFC的组合框(ComboBox)控件切换下拉样式
由于课题的需求需要做MFC串口程序,看了百度下载的串口助手的界面风格,发现这个设计很好 波特率的组合框只给出了5个可选数值,然后第6个选项是Custom,即手动输入. 实际上DCB结构的BaudRat ...
- java study1
java安装 java优势-跨平台:一次编写,到处运行. jdk开发工具包,提供了开发人员需要的开发工具.jdk中包含了jre jre java的运行环境,负责程序的运行,jre中,包含程序运行时需要 ...