委托

委托是执行安全的类,它的使用方式与类类似(即都需要定义再实例化),不同在于,类在实例化之后叫对象或类的实例,但委托在实例化后仍叫委托,委托可以把函数作为参数传递.

语法声明:

delegate <return type> <delegate-name> <parameter list>

委托使用的步骤:

  1. 声明委托类型(delegate关键字)
  2. 使用该委托类型声明一个委托变量并增加方法
  3. 调用委托执行方法

定义两个方法

public void ChineseSayHi()
{
Console.WriteLine("你好");
} public static void EnglishSayHi()
{
Console.WriteLine("Hello");
}

第一步:委托定义,根据返回值和参数定义不同的委托,意义:任何一个无返回值且无参数的方法都可以使用这个委托来调用

 public delegate void MyDelegate();

第二步:实例化委托变量并增加方法

MyDelegate myDelegate = new MyDelegate(new Program().ChineseSayHi); //C#1.0及更高版本中使用这种方式

也可以是静态方法

MyDelegate myDelegate = new MyDelegate(EnglishSayHi);

C# 2.0 提供了更简单的方法来编写前面的声明

MyDelegate myDelegate = EnglishSayHi

在 C# 2.0 和更高版本中,还可以使用匿名方法来声明和初始化委托

MyDelegate myDelegate = delegate () { Console.WriteLine("匿名方法初始化委托"); };

在 C# 3.0 和更高版本中,还可以通过使用 lambda 表达式声明和实例化委托

//TODO

第三步:调用委托执行方法,因为myDelegate是委托类型的一个变量.所以C#编译器会用myDelegate.Invoke()代替myDelegate(),所以这两种方式都可以

myDelegate();
myDelegate.Invoke();

委托数组

定义Math类提供两个静态方法接收一个double类型的参数,用于计算倍数和阶乘

class Math
{
public static double MultipleTwo(double value)
{
return value * ;
}
public static double Square(double value)
{
return value * value;
}
}

添加MathOperation操作方法,传递委托和double类型参数

class Program
{
public delegate double MyDelegate(double value); static void Main(string[] args)
{
//定义委托数组
MyDelegate[] myDelegates = {
Math.MultipleTwo,
Math.Square
};
//使用委托数组
for (int i = ; i < myDelegates.Length; i++)
{
MathOperation(myDelegates[i], 3.7);
MathOperation(myDelegates[i], 3.0);
}
Console.ReadKey();
}
public static void MathOperation(MyDelegate myDelegate, double value)
{
var result = myDelegate(value);
Console.WriteLine("Delegate is {0},value is {1}", myDelegate,result);
}
}

上面都是通过自己定义委托类型来使用的,除了为每个参数和返回类型定义一个新委托类型之外,还可以使用Action<T>和Func<T>委托

Action<T>:表示引用一个void返回类型的方法,可以传递最多16种不同的参数类型,没有泛型参数的Action类可调用没有参数的方法

Func<T>:Func<T>允许调用带返回类型的方法,可以传递16种不同类型的参数和一个返回类型,Func<out TResult>委托类型可以调用带返回类且无参数的方法

Action<T>实例

 Action action = EnglishSayHi;
action.Invoke();

Func<T>实例

Func<double, double>[] func = {
Math.MultipleTwo,
Math.Square
};

 总结

1:Action用于没有返回值的方法(参数根据自己情况进行传递)

2:Func恰恰相反用于有返回值的方法(参数根据自己情况传递)

3:记住无返回就用Action,有返回就用Func

多播委托
之前的每个委托都只包含一个方法调用,调用委托的次数与调用方法的次数相同,如果要调用多个方法,就需要多次显式调用这个委托,但是委托中也可以包含多个方法,称为多播委托,多播委托可以按顺序调用多个方法,为此委托的签名必须返回void,否则就只能得到委托最后调用的最后一个方法的结果

Func<double, double> func = Math.MultipleTwo;
func += Math.Square;
var result = func(3.0);
Console.WriteLine(result); MyDelegate myDelegate = Math.MultipleTwo;
myDelegate += Math.Square;
var result2 = myDelegate(3.0);
Console.WriteLine(result2);
Console.ReadKey(); 

只返回了3.0阶乘的值

这里需要再回头仔细了解一下看这种说法到底是否正确:即多播委托返回值必须为void

多播委托使用+=和-=,在委托中增加或删除方法调用

class Program
{
public delegate double MyDelegate(out double value); static void Main(string[] args)
{
Action action = Print.First;
action += Print.Second;
action();
Console.ReadKey();
}
}
class Print
{
public static void First()
{
Console.WriteLine("FirstMethod");
}
public static void Second()
{
Console.WriteLine("SecondMethod");
}
}

如果要使用多播委托,就要知道对同一个委托调用方法链的顺序并未正式定义,因为要避免编写依赖于特定顺序调用方法的代码

使用多播委托,意味着多播委托里包含一个逐个调用的委托集合,如果集合其中一个方法抛出异常.整个迭代就会停止

class Program
{
public delegate double MyDelegate(out double value); static void Main(string[] args)
{
Action action = Print.First;
action += Print.Second;
action();
Console.ReadKey();
}
}
class Print
{
public static void First()
{
Console.WriteLine("FirstMethod");
throw new Exception("Error");
}
public static void Second()
{
Console.WriteLine("SecondMethod");
}
}

委托只调用了第一个方法,因为第一个方法抛出了异常,委托的迭代停止,不再调用Second()方法

使用Delegate的GetInvocationList()方法自己迭代方法列表

            Action action = Print.First;
action += Print.Second;
Delegate[] delegates = action.GetInvocationList();
foreach (Action item in delegates)
{
try
{
item();
}
catch (Exception error)
{
Console.WriteLine(error.Message);
}
}
Console.ReadKey();

修改后,程序在捕获异常后,会迭代下一个方法

匿名类型

之前要使用委托,方法必须已经存在,还有另外一种使用委托的方式,即通过匿名方法,匿名方位作为委托参数的一部分;如果某个方法只被使用一次,这种情况下,除了创建委托语法的需要,没有必要创建独立的具名方法。因此,匿名方法应运而生

static void Main(string[] args)
{
Action action = delegate ()
{
Console.WriteLine("匿名方法打印Hello");
};
Action<string> action2 = delegate (string name)
{
Console.WriteLine("你好,我叫{0}", name);
};
Func<double, double> func = delegate (double value)
{
Console.WriteLine("Value={0}", value * );
return value * ;
};
action();
action2("Wang");
func(3.0);
Console.ReadKey();
}

lambda表达式

C#3.0开始,可以使用一种新的语法把实现代码赋予委托,这就是lambda表达式,Lambda表达式取代了匿名方法,作为编写内联代码的首先方式

lambda运算符"=>"左边列出了需要的参数,右边定义了赋予lambda变量的方法实现代码

无参数

Action action = () =>
{
Console.WriteLine("无参数");
};

一个参数

Action<string> action2 = param =>
{
Console.WriteLine("你好,我叫{0}", param);
};

 多个参数

Action<int, int> action2 = (a, b) =>
{
Console.WriteLine("Sum:{0}", a + b);
};

如果lambda表达式只有一句.方法块内就可以省略花括号和return语句,这时编译器会添加一条隐式的return语句

 Func<double, double> func = param => param * param;

等价于

Func<double, double> func = param =>
{
return param * ;
};

 闭包

通过lambda表达式可以访问表达式块外部的变量,称为闭包,编译器会创建匿名类,使用构造函数来传递外部变量,构造函数取决于从外部传递进来的变量个数

static void Main(string[] args)
{
int x = ;
Action<int> action = p =>
{
Console.WriteLine("lambda表达式调用外部变量,Sum :{0}", p + x);
};
Action<int> action2 = delegate (int p)
{
Console.WriteLine("匿名函数调用外部变量,Sum {0}", p + x);
};
action();
action2();
Console.ReadKey();
}

这里需要后续着重学习一下,包括闭包的陷阱等等

事件 

事件基于委托,为委托提供了一种发布/订阅机制.

事件定义语法

<访问修饰符> event 委托名 事件名;

看到一个孩子他妈叫他爸和儿子回家吃饭的例子,觉着很生动.这里就用这个例子学习一下

 class Program
{
static void Main(string[] args)
{
Mum mum = new Mum();
//事件订阅
mum.EatEvent += new Mum.myDelegate(new Son().Eat);
mum.EatEvent += new Mum.myDelegate(new Father().Eat);
mum.Call();
Console.ReadKey();
}
}
/// <summary>
/// 发布器
/// </summary>
public class Mum
{
//定义委托,用这个委托定义处理事件的方法类型
public delegate void myDelegate(); //根据委托定义事件,这里的事件是吃饭
public event myDelegate EatEvent; public void Call()
{
Console.WriteLine("Mum:饭做好了,过来吃饭");
//触发事件
EatEvent();
}
}
class Son
{
//事件处理方法,与Mum类中的委托方法签名一致
public void Eat()
{
Console.WriteLine("Son:游戏打完我就过去");
}
}
class Father
{
public void Eat()
{
Console.WriteLine("Father:好的我马上过来");
}
}

 event与EventHandler

待补充...

参考:

http://www.cnblogs.com/jujusharp/archive/2011/08/04/2127999.html

https://www.cnblogs.com/HQFZ/p/4903400.html

https://www.cnblogs.com/wangjiming/p/8300103.html

委托/lambda表达式/事件的更多相关文章

  1. 委托+内置委托方法+多播委托+lambda表达式+事件

    委托概念:如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托: 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字 ...

  2. 委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件【转】

    1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委 ...

  3. Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

    一.多态 里氏替换原则: 任何能用基类的地方,可以用子类代替,反过来不行.子类能够在基类的基础上增加新的行为.面向对象设计的基本原则之一. 开放封闭原则: 对扩展开放,意味着有新的需求或变化时,可以对 ...

  4. C# Note2:委托(delegate) & Lambda表达式 & 事件(event)

    前言 本文主要讲述委托和Lambda表达式的基础知识,以及如何通过Lambda表达式实现委托调用,并阐述.NET如何将委托用作实现事件的方式. 参考:C#高级编程 1.什么是委托(delegate)? ...

  5. (28)C#委托,匿名函数,lambda表达式,事件

    一.委托 委托是一种用于封装命名和匿名方法的引用类型. 把方法当参数,传给另一个方法(这么说好理解,但实际上方法不能当参数,传入的是委托类型),委托是一种引用类型,委托里包含很多方法的引用 创建的方法 ...

  6. C#编程 委托 Lambda表达式和事件

    委托 如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字段和方 ...

  7. 委托 lambda表达式浅显理解

    方法不能跟变量一样当参数传递,怎么办,C#定义了委托,就可以把方法当变量一样传递了,为了简单,匿名方法传递,省得再声明方法了:再简单,lambda表达式传递,比匿名方法更直观. public dele ...

  8. C#学习笔记三(委托·lambda表达式和事件,字符串和正则表达式,集合,特殊的集合)

    委托和事件的区别 序号 区别 委托 事件 1 是否可以使用=来赋值 是 否 2 是否可以在类外部进行调用 是 否 3 是否是一个类型 是 否,事件修饰的是一个对象 public delegate vo ...

  9. C# 委托(delegate)、泛型委托和Lambda表达式

    目录 # 什么是委托 # 委托声明.实例化和调用 1.声明 2.委托的实例化 3.委托实例的调用 4.委托完整的简单示例 #泛型委托 1.Func委托 2.Action委托 3.Predicate委托 ...

随机推荐

  1. geos 3.6.3库windows版本 已编译完成的32位版本和64位版本

    网上教编译方法的很多,直接分享编译完成的很少. 我就把编译完成的分享出来吧. ​geos-3.6.3.tar.bz2 (Changes) 版本的 https://trac.osgeo.org/geos ...

  2. C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别

    C#语法——泛型的多种应用   本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...

  3. 使用xshell+xmanager+pycharm搭建pytorch远程调试开发环境

    1. 相关软件版本 xshell: xmanager: pycharm: pycharm破解服务器:https://jetlicense.nss.im/ 2. 将相应的软件安装(pojie好) a&g ...

  4. mysql 动态增加列,查找表中有多少列,具体什么列。 通过JSON生成mysql表 支持子JSON

    好消息, 程序员专用早餐机.和掌柜说 ideaam,可以节省20元. 点击链接  或復·制这段描述¥k3MbbVKccMU¥后到淘♂寳♀ 或者 淘宝扫码 支持下同行哈 ---------------- ...

  5. C# 托管内存与非托管内存之间的转换

    c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...

  6. window10下TensorFlow-gpu环境搭建

    安装python 下载python3.5.4 https://www.python.org/downloads/release/python-354/ 选择Windows x86-64 executa ...

  7. Python AES_ECB_PKCS5加密代码

    https://blog.csdn.net/u010978840/article/details/79035463 ****************************************** ...

  8. SpringMvc的Url映射和传参案例(转)

    Springmvc的基本使用,包括url映射.参数映射.页面跳转.ajax和文件上传 以前学习的时候写的代码案例,今天整理笔记的时候找到了,很久没有来园子了,发上来当个在线笔记用吧,免的时间长了又忘了 ...

  9. C++ 智能指针七

    /* 智能指针weak_ptr */ #include <iostream> #include <string> #include <memory> /* weak ...

  10. log4net 如何关闭Nhibernate产生的大量日志

    [参考文献]Log4Net指南 非常完善的Log4net详细说明 C# 使用Log4Net记录日志(进阶篇) 此问题困扰良久 良久 良久 appender filter ,show_sql false ...