委托:

还记得C++里的函数指针么?大家可以点击这里查看一下以前的笔记。C#的委托和C++中的函数指针效果一致。

当我们需要将函数作为对象进行传递和使用时就需要用到委托。

下面我们看一个例子:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
//声明委托的实例
ProcessDelegate pd; //指定委托的函数
pd = Multiply;
Console.WriteLine(pd(, )); //指定委托的函数
pd = Divide;
Console.WriteLine(pd(, )); //将委托作为参数传递
Func1(pd);
//将函数直接作为参数传递
Func1(Multiply); Console.ReadKey();
} /// <summary>
/// 声明一个委托.
/// </summary>
delegate double ProcessDelegate(double param1, double param2); static double Multiply(double param1, double param2)
{
return param1 * param2;
} static double Divide(double param1, double param2)
{
return param1 / param2;
} /// <summary>
/// 参数为委托类型的函数.
/// </summary>
static void Func1(ProcessDelegate pd)
{
Console.WriteLine(pd(, ));
}
}
}

运行的结果如下:


初始化定义和委托推断:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate string GetAString(); static void Main(string[] args)
{
int x = ;
//这里我称为初始化定义, 注意不能写成 x.ToString()
GetAString method = new GetAString(x.ToString);
Console.WriteLine(method()); x = ;
//通过委托推断可以简化代码编写, 注意不能写成 x.ToString()
GetAString method2 = x.ToString;
Console.WriteLine(method2()); Console.ReadKey();
}
}
}

多播委托:

多播委托支持“+”“-”操作符,可以添加多个方法到同一个委托中,当委托被执行时,并不会按照添加的顺序依次调用函数,调用顺序是无法保证的。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate void DoubleOp(double value); public static void Func1(double value)
{
double result = value * ;
Console.WriteLine("Func1 value: {0}, result: {1}", value, result);
} public static void Func2(double value)
{
double result = value * value;
Console.WriteLine("Func2 value: {0}, result: {1}", value, result);
} static void Main(string[] args)
{
DoubleOp op = Func1;
//添加一个方法
op += Func2; op();
Console.WriteLine();
op();
Console.WriteLine(); //去掉一个方法
op -= Func1; op(); Console.ReadKey();
}
}
}

下面是运行的结果:

 Func1 value: , result:
Func2 value: , result: Func1 value: , result:
Func2 value: , result: Func2 value: , result:

匿名函数:

使用时直接进行定义的函数。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate string GetString(float num); static void Main(string[] args)
{
//定义匿名函数
GetString m = delegate(float num)
{
return num.ToString();
};
Func(m, 10.5f); //直接传递匿名函数
Func(delegate(float num)
{
num *= 2.0f;
return num.ToString();
}, 20.5f); Console.ReadKey();
} static void Func(GetString method, float num)
{
Console.WriteLine("Func: " + method(num));
}
}
}

下面是运行的结果:

 Func: 10.5
Func:

Lambda表达式:

Lambda表达式可以用来简化匿名函数的写法,如果把上面的示例改为Lambda表达试则如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate string GetString(float num); static void Main(string[] args)
{
//使用表达式进行简写
GetString m = num =>
{
return num.ToString();
};
Func(m, 10.5f); //直接传递表达试
Func(num =>
{
num *= 2.0f;
return num.ToString();
}, 20.5f); Console.ReadKey();
} static void Func(GetString method, float num)
{
Console.WriteLine("Func: " + method(num));
}
}
}

Lambda表达式可以去掉函数参数的类型,因为该类型编译器可以从上下文中获得。如果存在多个参数则需要添加括号,如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate string GetString(float num, int num2); static void Main(string[] args)
{
//使用表达式进行简写
GetString m = (num, num2) =>
{
return num.ToString() + "," + num2.ToString();
};
Func(m, 10.5f, ); //直接传递表达试
Func((num, num2) =>
{
num *= 2.0f;
num += num2;
return num.ToString();
}, 20.5f, ); Console.ReadKey();
} static void Func(GetString method, float num, int num2)
{
Console.WriteLine("Func: " + method(num, num2));
}
}
}

下面是运行的结果:

 Func: 10.5,
Func:

如果代码仅有一行还可以省略return和大括号,如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
delegate string GetString(float num, int num2); static void Main(string[] args)
{
//使用表达式进行简写
GetString m = (num, num2) => num.ToString() + "," + num2.ToString();
Func(m, 10.5f, ); //直接传递表达式
Func((num, num2) => num.ToString() + "," + num2.ToString(), 20.5f, ); Console.ReadKey();
} static void Func(GetString method, float num, int num2)
{
Console.WriteLine("Func: " + method(num, num2));
}
}
}

下面是运行的结果:

 Func: 10.5,
Func: 20.5,

这里引入了一个新的知识点协变和抗变,大家可以自行搜索,或者查看协变和抗变的文章点击这里

事件:

C#里的事件使用event关键字定义,无需实例化就可以使用,可以将其看做一个特殊的委托对象,下面我们看看一个例子。

EventDispatcher.cs(用来定义和发送特定事件的类):

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
/// <summary>
/// 事件发送类.
/// </summary>
class EventDispatcher
{
/// <summary>
/// 定义特定的事件委托, 注意不要有返回值.
/// </summary>
/// <param name="sender">发送者.</param>
/// <param name="args">附带的参数.</param>
public delegate void MyEventHandler(object sender, MyEventArgs args); /// <summary>
/// 事件对象, 所有的回调都可以添加到该对象上, 不需要实例化就能使用.
/// </summary>
public event MyEventHandler onCustom; /// <summary>
/// 构造函数.
/// </summary>
public EventDispatcher()
{
} /// <summary>
/// 发送一个自定义事件.
/// </summary>
/// <param name="data">数据.</param>
public void dispatchCustom(String data)
{
onCustom(this, new MyEventArgs(data));
}
} /// <summary>
/// 自定义事件参数类.
/// </summary>
class MyEventArgs : EventArgs
{
public String data; public MyEventArgs(String data)
{
this.data = data;
}
}
}

Program.cs(主程序,测试类):

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
new Program(); Console.ReadKey();
} public Program()
{
EventDispatcher ed = new EventDispatcher(); //第一种方式
EventDispatcher.MyEventHandler meh = new EventDispatcher.MyEventHandler(CustomHandler);
ed.onCustom += meh;
ed.dispatchCustom("Hello One!");
ed.onCustom -= meh; //第二种方式
ed.onCustom += new EventDispatcher.MyEventHandler(CustomHandler);
ed.dispatchCustom("Hello Two!");
//下面两种方式都可以删除注册的事件处理函数
ed.onCustom -= new EventDispatcher.MyEventHandler(CustomHandler);
//ed.onCustom -= CustomHandler; //简写方式
ed.onCustom += CustomHandler;
ed.dispatchCustom("Hello Three!");
ed.onCustom -= CustomHandler; //匿名函数写法
ed.onCustom += delegate(object sender, MyEventArgs args)
{
Console.WriteLine("Event Handler (delegate) : " + args.data);
};
ed.dispatchCustom("Hello Four!"); //Lambda 写法
ed.onCustom += (sender, args) =>
{
Console.WriteLine("Event Handler (lambda) : " + args.data);
};
ed.dispatchCustom("Hello Five!"); //简写 Lambda
ed.onCustom += (sender, args) => Console.WriteLine("Event Handler (lambda) : " + args.data);
ed.dispatchCustom("Hello six!");
} private void CustomHandler(object sender, MyEventArgs args)
{
Console.WriteLine("Event Handler : " + args.data);
}
}
}

下面是程序运行的结果:

 Event Handler : Hello One!
Event Handler : Hello Two!
Event Handler : Hello Three!
Event Handler (delegate) : Hello Four!
Event Handler (delegate) : Hello Five!
Event Handler (lambda) : Hello Five!
Event Handler (delegate) : Hello six!
Event Handler (lambda) : Hello six!
Event Handler (lambda) : Hello six!

委托、匿名函数、Lambda表达式和事件的学习的更多相关文章

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

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

  2. 【Unity|C#】基础篇(9)——匿名函数 / Lambda表达式

    [学习资料] <C#图解教程>(第13章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  3. 函数:lambda表达式 - 零基础入门学习Python021

    函数:lambda表达式 让编程改变世界 Change the world by program lambda表达式 Python允许使用lambda关键字来创建匿名函数.我们提到一个新的关键字:匿名 ...

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

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

  5. 匿名函数 lambda表达式(lambda expression)

    阅读g2log时,发现有两行代码居然看不懂. 1. auto bg_call =  [this, log_directory]() {return pimpl_->backgroundChang ...

  6. C#多线程+委托+匿名方法+Lambda表达式

    线程 下面是百度写的: 定义英文:Thread每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它 ...

  7. Qt中使用匿名函数lambda表达式

    一.为什么要使用匿名函数lamdba 首先,lambda表达式可以使代码变得简单,C++中,一个lambda表达式表示一个可调用的代码单元.如代码: #include <QCoreApplica ...

  8. Python匿名函数——lambda表达式

    如果要定义的函数很简单,一个return语句就能搞定,可以使用lambda表达式来定义, lambda表达式的语法如下: lambda parameters: expression lambda表达式 ...

  9. python做中学(八)匿名函数lambda的用法

    匿名函数,顾名思义即没有名称的函数,和def定义的函数的最大区别在于匿名函数创建后返回函数本身(即匿名函数不需要return来返回值),表达式本身结果就是返回值,而def创建后则赋值给一个变量名,在P ...

随机推荐

  1. HeadFirst设计模式之组合模式

    一. 1.The Composite Pattern allows us to build structures of objects in the form of trees that contai ...

  2. 如何用DELPHI编程修改外部EXE文件的版本信

    右击里面有修改 点开直接修改就可以了吧. DELPHI 里程序的版本信息怎么是灰色的,无法更改 耐心读以下说明,应该能解决你的问题,如果不能解决,请Hi我~ 如何给自己的dll文件添加版本信息呢? 首 ...

  3. node.js 模块和包

    Node.js 的模块和包机制的实现参照了 CommonJS 的标准,但并未完全遵循.不过两者的区别并不大,一般来说你大可不必担心,只有当你试图制作一个除了支持 Node.js之外还要支持其他平台的模 ...

  4. Hadoop伪分布模式配置部署

    .实验环境说明 注意:本实验需要按照上一节单机模式部署后继续进行操作 1. 环境登录 无需密码自动登录,系统用户名 shiyanlou,密码 shiyanlou 2. 环境介绍 本实验环境采用带桌面的 ...

  5. Spring-Data-JPA学习

    Spring-Data-JPA结构图 网址: http://blog.sina.com.cn/s/blog_667ac0360102ecsf.html

  6. 1126. Magnetic Storms(单调队列)

    1126 最简单的单调队列应用吧 单调队列是指在一个队列中各个元素单调 递增(或者递减),并且各个元素的下标单调 递增. 单调队列的大体操作 进队时,将进队的元素为e,从队尾往前扫描,直到找到一个不大 ...

  7. LeeCode Algorithm #3 Longest Substring Without Repeating Characters

    一开始以为是不连续的,其实要求子串是连续的.想法:two-pointer O(n)时间,再借助256大小的int数组.两个下标i,j(i<=j).对于i=0,找到最右侧的字符不重复的下标的后一位 ...

  8. Repeater的ItemCommand事件(LinkButton)

    Repeater的ItemCommand事件,就是在里面加一个超链接的按钮,所有按钮都指向同一个事件,就是ItemCommand事件. 至于如何区分是点击的什么按钮,还有传的值,需要用到LinkBut ...

  9. jquery 上传空间uploadify使用笔记

    基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,删除已上传文件. 要求使用jquery1.4或以上版本,flash player 9.0.24以上. 有两个 ...

  10. Maven使用教程

    一.Maven介绍 我们在开发项目的过程中,会使用一些开源框架.第三方的工具等等,这些都是以jar包的方式被项目所引用,并且有些jar包还会依赖其他的jar包,我们同样需要添加到项目中,所有这些相关的 ...