一、引用方法

委托是寻址方法的.NET版本。委托是类型安全的类,它定义了返回类型和参数的类型。委托是对方法的引用,也可以对多个方法进行引用,委托可以理解为指向方法地址的指针。

如:delegate int ReturnIntHandler(int a,int b);//int是返回类型,a和b是引用类型,这是委托执行的方法必须满足如下格式:int method(int param1,int param2);

二、委托

当要把方法传递给其它方法时,需要使用委托。委托是一种特殊类型的对象,其特殊之处在于,我们以前定义的所有对象都包含数据,而委托包含的只是一个或多个方法的地址。

1、声明委托

委托使用关键字 delegate 进行定义。

定义委托基本上就是定义一个新类,所以可以在定义类的任何相同地方定义委托。可以在委托定义上应用常见的访问修饰符:public、private、protected等。其访问作用域也雷同于类。

2、使用委托

为了减少输入量,只需要委托实例,就可以只传递地址的名称。这称为委托推断。

delegate int CalculateMethodInvoker(int x, int y);
class Program
{
static void Main(string[] args)
{
//创建委托对象
CalculateMethodInvoker calculateMethodInvoker = CalculateHelper.Sum;
//等同于CalculateMethodInvoker calculateMethodInvoker = new CalculateMethodInvoker(CalculateHelper.Sum);//委托的实例化,指向Sum方法,其实委托也是可以定义,实例化调用的,不只是lambda表达式的调用方式
int x = , y = ;
Console.WriteLine("x,y相加:{0}", Calculate(calculateMethodInvoker, x, y));
calculateMethodInvoker = CalculateHelper.Multiply;
Console.WriteLine("x,y相乘:{0}", Calculate(calculateMethodInvoker, x, y));
Console.ReadKey();
}
public static int Calculate(CalculateMethodInvoker calculateMethodInvoker, int x, int y)
{
//return calculateMethodInvoker(x, y);
//return calculateMethodInvoker.Invoke(x, y);//是不是当前线程都可以
IAsyncResult result = calculateMethodInvoker.BeginInvoke(x, y, null, calculateMethodInvoker);//异步,这里只是做展示,EndInvoke类似于async中的await,这里不能实现异步效果
return calculateMethodInvoker.EndInvoke(result);
} }
public class CalculateHelper
{
public static int Sum(int x, int y)
{
return x + y;
}
public static int Multiply(int x, int y)
{
return x * y;
}
}

3、Action<T>和Func<T>委托

除了为每个参数和返回类型定义一个新的委托类型外,还可以使用Action<T>和Func<T>委托。

泛型Action<T>委托表示引用一个void返回类型的方法,没有泛型参数的Action类可调用没有参数的方法,如Action 等价于 delegate void mydelegate;  Action<int,int>等价于delegate void mydelegate(int param1,int param2);

泛型Func<T>委托表示引用一个有返回值的方法,泛型的最后一个参数时Func的返回值类型,如Func<int,int,bool>,等价于delegate bool mydelegate(int param1,int param2);

4、多播委托

委托也可以包含多个方法。这种委托成为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。多播委托识别运算符“-”、“+”、“-=”、“+=”以从委托中增加或删除方法调用。

如:

class Program
{
static void Main(string[] args)
{
Action<int, int> calFunc = CalculateHelper.Sum;
calFunc += CalculateHelper.Multiply;//多播加
int x = , y = ;
Calculate(calFunc, x, y);
calFunc =calFunc- CalculateHelper.Multiply;//多播减
Calculate(calFunc, x, y);
Console.ReadKey();
}
public static void Calculate(Action<int, int> calculateMethodInvoker, int x, int y)
{
Console.WriteLine("运行结果:");
//calculateMethodInvoker(x, y);
foreach (Action<int, int> item in calculateMethodInvoker.GetInvocationList())//遍历,这里需要转为为当前类型委托
{
try
{
item(x, y);//执行委托指向方法
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}

如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。解决的方法是,使用Delegate类中定义的GetInvocationList()方法获取Delegate对象数组,再使用循环遍历执行,在过程中捕获异常,来继续下一次迭代。

5、匿名方法

匿名方法是用作委托的参数的一段代码。

如:

Action<int, int> calFunc = delegate (int i, int j)
{
Console.WriteLine("x,y相加:{0}", i + j);
};

在匿名方法中不可使用跳转语句(break、goto或continue),在匿名方法内部不能访问不安全代码,不能访问在匿名方法外部使用的ref和out参数。

三、lambda表达式

C#3.0后,可以使用lambda把实现代码赋予委托,只要有委托参数类型的地方,就可以使用lambda表达式。

如:

Action<int, int> calFunc = (i, j) =>
{
Console.WriteLine("x,y相加:{0}", i + j);
};

1、参数

lambda表达式有几种定义参数的方式。如果只有一个参数,只写出参数名就足够了。如果除一个参数以外,需要圆括号把参数名括起来。

例子:

Action<int> one = i =>
{
//method body
};
Action<int, int> two = (i, j) =>
{
//method body
};

2、多行代码

如果lambda表示只有一条语句,在方法块内就不需要花括号和return语句,因为编译器会隐式添加return。

如:

Func<int> lambdaOne = () => 0;

如果实现代码超过一行,就需要使用return语句显式返回。

如:

{
int i = 0;
i++;
++i;
return i;
};

3、闭包

通过lambda表达式可以访问lambda表达式块外部的变量。这称为闭包。

如:

int param = 10;
Action<int> lambdaSecond = (i) =>
{
Console.WriteLine(i + param);
};
lambdaSecond(3);
Console.ReadKey();

四、事件

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

如:

class Program
{
static void Main(string[] args)
{
AlarmClock alarmClock = new AlarmClock();
Student zsStudent = new Student("张三");
alarmClock.ItsGetUpClockEvent += zsStudent.ItsGetUpClock;
alarmClock.ItsGetUpClock();
Student lsStudent = new Student("李四");
//WeakEventManager<AlarmClock, EventArgs>.AddHandler(alarmClock, "ItsGetUpClockEvent", lsStudent.ItsGetUpClock);
////弱事件,System.Windows,WPF中经常用到
//alarmClock.ItsGetUpClock();
Console.ReadKey();
} }
//事件发布类
public class AlarmClock
{
public event EventHandler<EventArgs> ItsGetUpClockEvent;
public void ItsGetUpClock()
{
Console.WriteLine("时间到,起床了!");
ItsGetUpClockEvent?.Invoke(this, new EventArgs());//判断是否订阅事件
}
}
//事件侦听类
public class Student
{
public string Name { get; set; }
public Student(string name)
{
this.Name = name;
}
public void ItsGetUpClock(object sender, EventArgs e)
{
Console.WriteLine("{0}关掉闹钟,起床了。", Name);
}
}

事件最常用的地方是Winform和Wpf窗体中,而Invoke的经典使用场景如下(非当前线程更改窗体文本):

 private void ShowExecLog(string log)
{
if (this.richTextBox1.InvokeRequired)//判断是否是当前线程
{
this.richTextBox1.Invoke(new ShowLogHandler(ShowLog), log);
}
else
{
this.richTextBox1.Text += log;
}
} public void ShowLog(string log)
{
this.richTextBox1.Text += log;
} public delegate void ShowLogHandler(string log);

c# delegate知识的更多相关文章

  1. [.NET] C# 知识回顾 - 委托 delegate (续)

    C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...

  2. [C#] C# 知识回顾 - 委托 delegate

    C# 知识回顾 - 委托 delegate [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6031892.html 目录 What's 委托 委托的属性 ...

  3. C#基础知识六之委托(delegate、Action、Func、predicate)

    1. 什么是委托 官方解释 委托是定义方法签名的类型,当实例化委托时,您可以将其实例化与任何具有兼容签名的方法想关联,可以通过委托实例调用方法. 个人理解 委托通俗一点说就是把一件事情交给别人来帮助完 ...

  4. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  5. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  6. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  7. [C#] C# 知识回顾 - 学会使用异常

    学会使用异常 在 C# 中,程序中在运行时出现的错误,会不断在程序中进行传播,这种机制称为“异常”. 异常通常由错误的代码引发,并由能够更正错误的代码进行 catch. 异常可由 .NET 的 CLR ...

  8. [C#] C# 知识回顾 - 异常介绍

    异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...

  9. [.NET] C# 知识回顾 - Event 事件

    C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...

随机推荐

  1. C# HttpWebRequest post提交数据,提交对象

    1.客户端方法 //属于客户端 //要向URL Post的方法 public void PostResponse() { HttpWebRequest req = (HttpWebRequest)Ht ...

  2. node必学的Hello World实现--服务器实现

    node是JavaScript运行在后端的一种实现.而后端语言,不管是php,java都需要一个服务器才能跑起来,node如是. node的服务器较php而言,少了单独安装服务器的步骤,node的服务 ...

  3. 载入其他同名源文件导致vs编译错误

    今天下午工程编译的时候总是通不过,提示1,某个类没有某个成员,可是我去该类的头文件下查看,确实包括了这个成员啊.2,没有某个类,可是我明明定义了的. 检查了好久才发现 原来是,我打开了其他工程下的某一 ...

  4. 委托,事件,lambda表达式

    开篇说明三个点: 委托是一种类型 事件是委托的实例 lambda表达式是一个方法(匿名方法) [未完待续]

  5. OBJ文件

    OBJ文件是Alias|Wavefront公司为它的一套基于工作站的3D建模和动画软件"Advanced Visualizer"开发的一种标准3D模型文件格式,很适合用于3D软件模 ...

  6. openstack之Glance介绍

    什么是Glance glance即image service(镜像服务),是为虚拟机的创建提供镜像服务 为什么要有Glance 我们基于openstack是构建基本的Iaas平台对外提供虚机,而虚机在 ...

  7. BZOJ4700 适者(贪心+cdq分治+斜率优化)

    首先考虑怎么安排攻击顺序.显然如果攻击了某台兵器就应该一直连续攻击直到将其破坏,破坏所需时间可以直接算出来,设其为b.假设确定了某个破坏顺序,如果交换相邻两个兵器,显然不会对其他兵器造成影响,两种顺序 ...

  8. AOP拦截+权限验证+返回默认接口对象

    接口如:public IList<string> TestAOP(string token); public IMethodReturn Invoke(IMethodInvocation ...

  9. [CF785E]Anton and Permutation

    题目大意:有一串数为$1\sim n(n\leqslant2\times10^5)$,$m(m\leqslant5\times10^4)$次询问,每次问交换位置为$l,r$的两个数后数列中逆序对的个数 ...

  10. [SCOI2007]组队 差分

    题面:[SCOI2007]组队 题解: 一开始固定H然后找性质找了很久也没有找到任何有用的东西...... 然后大佬告诉我一个神奇的方法... 首先我们化一波式子: 设$H$表示高度的最小值,$V$表 ...