委托:

还记得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. Qt: 读写二进制文件(写对象, 原始数据等)

    #include <iostream>#include <QFile>#include <QImage>#include <QMap>#include ...

  2. ERDAS IMAGINE 9.2安装破解方法

    Install the application. Copy the license.dat and ERDAS.exe to C:\Program Files\Leica Geosystems\Sha ...

  3. Windows 8 自带定时关机的4种实现方法

    问题描述:前几天发布了一篇文章[ Windows 7/8 自带定时关机命令 ],文章中的用到的命令我在Windows 7都运行成功,但没有在Windows 8 上进行测试,因为我认为Windows 8 ...

  4. 结构体 typedef struct hash_cell_struct hash_cell_t;

    typedef struct hash_cell_struct hash_cell_t; struct hash_cell_struct{ void* node; /*!< hash chain ...

  5. asp mvc 路由

    public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Workflo ...

  6. [HDU 1695] GCD

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  7. C#字符串与char数组互转!

    字符串转换成Char数组string str="abcdefghijklmnopqretuvwxyz";char[] chars=str.ToCharArray(); char数组 ...

  8. 深入理解Arrays.sort()

    两种方法: 1.类本来就实现java.lang.Comparable接口,使类本身就有比较能力.接口实现compareTo方法,次方法接收另一个Object为参数,如果当前对象小于参数则返回负值,如果 ...

  9. Java集合类:AbstractCollection源码解析

    一.Collection接口 从<Java集合:整体结构>一文中我们知道所有的List和Set都继承自Collection接口,该接口类提供了集合最基本的方法,虽然List接口和Set等都 ...

  10. Android学习的一些问题

    如何让Service常驻后台? 如何让App自启动? 如何让App自动更新? Handler Adapter Bundle Application getXXX()