委托:

还记得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. Sqlmap基础(二)

    sqlmap.py -r req1.txt --dbms Oracle --risk

  2. LINUX ulimit命令

    概述 系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何在有限资源的条件下保证程序的运作,ulimit 是我们在处理这些问题时,经常使用的一种简单手段.ulimit 是一 ...

  3. HTML DOM与XML DOM之间,既有区别

    http://kb.cnblogs.com/page/74971/ HTML文档可以使用Core API和HTML API两者: 而XML文档只能使用Core API. 换句话说,HTML与XML重叠 ...

  4. jquery的smartWizard插件使用方法

    jquery 的smartWizard插件常用在一些向导式的,按步骤的功能中,是的用户按照我们设定的步骤进行操作,这样一方面有较好的用户体验,可以将庞大的表格 数据分解成多个步骤,是的每个步骤的数据量 ...

  5. CentOS 6.4 编译安装Mysql 5.6.14

    概述: CentOS 6.4下通过yum安装的MySQL是5.1版的,比较老,所以就想通过源代码安装高版本的5.6.14. 正文: 一:卸载旧版本 使用下面的命令检查是否安装有MySQL Server ...

  6. 命令行下玩VC

    说明:(1)转载请注明出处:http://www.cnblogs.com/opangle/p/4298155.html (2)以下以VS2013为例,并假设VC安装路径为%VC_INSTALL_PAT ...

  7. Java web 项目 tomcat部署方式.

    本地做Java Web项目的时候常常会用到tomcat部署测试的问题, 这里介绍项目的部署方法: 1,配置文件的形式: 例如: 你的项目目录为:f:\workspaces\MyProject,此时使用 ...

  8. JDK版本1.6和6.0到底指什么

    Both version numbers (1.6.0 and 6) are used to identify this release of the Java Platform. Version 6 ...

  9. 巧用CSS文件愚人节恶搞(转)

    明天就是4月1日愚人节了,也就是那个可适度开玩笑.整蛊的日子了.如果你想和那些要上网的朋友或同事开个极客式玩笑,那就来试试这个国外网友Wes Bos分享的 CSS 文件吧. 一.打开浏览器的 Cust ...

  10. C#中如何截取Windows消息来触发自定义事件

    原文 C#中如何截取Windows消息来触发自定义事件 在c#windows开发中,我们常常会遇到拦截windows消息,来触发某个特定任务的问题. 由于目前使用c#的开发人员非常多,而且大多数c#程 ...