什么是委托?                                                                                      

  委托类似于C语言中的函数指针,更类似于C++11中的std::function,但更安全也更强大。委托如同类一样是一个类型,只不过类的实例指向一个对象,而委托的实例指向一个方法,该方法可以是成员方法也可以是静态方法。

委托的基本使用

  下面介绍委托的两种初始化和调用方式

using System;

namespace Delegate01
{
class Program
{
public delegate string MyDelegate(string s); //定义一个委托,其返回值是string,参数为空
static void Main(string[] args)
{
//委托初始化和调用的第一种方式。该例子中绑定的方法为成员方法
Program self = new Program();
MyDelegate d1 = new MyDelegate(self.ShowSelf);
Console.WriteLine(d1.Invoke("tianya")); //委托初始化和调用的第二种方式,这种方式因为更简便,所以更常用。该例子中绑定的方法为静态方法
MyDelegate d2 = Program.Show;
Console.WriteLine(d2("feng"));
} string ShowSelf(string str)
{
Console.WriteLine("ShowSelf str:" + str);
return "ShowSelf Ret";
} static string Show(string str)
{
Console.WriteLine("Show str:" + str);
return "Show Ret";
}
}
}

Action委托和Func委托

  Ation 委托可以用来替代返回值是 void 的委托,泛型参数表示委托的参数,至多可以传递16个参数,其中没有泛型参数的Action类可调用没有参数的方法。

  Func 委托可以用来替代返回值不是 void 的委托,最后一个泛型参数表示返回类型,其它参数表示委托的参数,至多可以传递16个参数和一个返回类型,Func委托至少包括一个泛型参数,可调用没有参数的方法。

  Action 和 Func 委托并没有特殊之处,只是为了方便使用而提出的,尤其是把委托做为函数的某个参数时,不需要显式定义一个委托类型。

using System;

namespace Delegate02
{
class Program
{
public delegate int MyDelegate(int i, int j); //定义一个委托
static void Main(string[] args)
{
CallDelegate(Add); //方法参数是一个委托定义
CallDelegateWithFunc(Add); //方法参数是一个Func委托
CallDelegateWithAction(Show); //方法参数是一个Action委托
} //如果不使用Action和Func,将委托做为参数,必须要先定义一个委托类型
static void CallDelegate(MyDelegate d)
{
d(,);
} //如果使用Action和Func,将委托做为参数,就不需要先行定义。明显这种写法更简洁清晰
static void CallDelegateWithFunc(Func<int,int,int> d)
{
d(,);
} static void CallDelegateWithAction(Action d)
{
d();
} static int Add(int i, int j)
{
Console.WriteLine("sum:" + (i + j).ToString());
return i + j;
} static void Show()
{
Console.WriteLine("Show");
}
}
}

匿名方法和lambda表达式

using System;

namespace Delegate03
{
class Program
{
static void Main(string[] args)
{
//匿名方法使用 delegate关键字修饰,主要用于一些只需要使用一次的方法,这样就不需要显式去定义。
Func<int,int,int> f1= delegate(int i,int j) { return i + j; };
Console.WriteLine(f1(, )); //Lambda表达式是匿名方法的一种更简化写法
Func<int, int, int> f2 = (i, j) => { return i + j; };
Console.WriteLine(f2(, )); //Lambda的参数只有一个的时候,可以不需要小括号,当函数体中的语句只有一句的时候,可以不加上大括号和return关键字
Action<string> a = s => Console.WriteLine(s); //等同于 Action<string> a = (s) => { Console.WriteLine(s); };
a("Action");
}
}
}

多播委托

  所谓多播委托,是指一个委托可以注册多个方法,可以使用 +,+=,-,-= 操作符,在调用委托时,可能触发多个方法调用。

using System;

namespace Delegate04
{
class Program
{
static void Main(string[] args)
{
//多播委托
Action<string> a = Run;
a += Jump;
a("Cat"); //使用Lambda实现的多播委托
Action<string> a1 = name => Console.WriteLine(name + "->Run");
a1 += name => Console.WriteLine(name + "->Jump");
a1("Mouse"); //使用有返回值的多播委托,因为有返回值,这种多播委托实际上没有效果,只会调用最后一个注册的方法。这个要格外注意
Func<int, int, int> f = Add;
f += Mul;
Console.WriteLine(f(, )); //多播委托在调用时,如果其中一个方法调用抛出异常,则后续的方法将不会执行。
//可以通过 GetInvocationList 方法获取该委托对象上已注册的方法列表,然后依次执行
Delegate[] delegates = a.GetInvocationList();
foreach (Action<string> action in delegates)
{
action("Rabbit");
}
//使用 DynamicInvoke 方法可以在委托的类型不可知的情况下通过反射来调用,但对性能有影响。
foreach (var action in a.GetInvocationList())
{
action.DynamicInvoke("Rabblit");
}
} static void Run(string name)
{
Console.WriteLine(name + "->Run");
} static void Jump(string name)
{
Console.WriteLine(name +"->Jump");
} static int Add(int i, int j)
{
return i + j;
} static int Mul(int i,int j)
{
return i * j;
} }
}

事件

  事件是一种受约束的委托,通过 event 关键字修饰,事件只能定义为类的成员,且只能在当前类中被调用,你可以理解它为私有的(但其实不是,而且必须不是,因为其它类需要注册该委托)。那么为什么要弄出事件这个东西来呢?主要是为了实现发布\订阅机制,在发布者类中定义一个事件,并由发布者类中的一个公有方法调用该事件,而诸多订阅者则可以为事件注册方法,注册好之后,调用发布者中的公有方法即可触发事件。如果使用普通的委托,会带来一个问题,即订阅者也可以直接调用委托。

using System;

namespace Delegate05
{ class Cat
{
public event Action action; //当该方法调用后,会回调定义好的委托,继续执行已经注册的方法
public void Shout()
{
Console.WriteLine("Cat Shout!");
action();
}
} class Mouse
{
private string name;
public Mouse(string name)
{
this.name = name;
}
public void Run()
{
Console.WriteLine("name:" + name + " Run!");
} public void Jump()
{
Console.WriteLine("name:" + name + " Jump!");
}
} class Program
{
public static void Main()
{
Mouse mouse1 = new Mouse("mouse1");
Mouse mouse2 = new Mouse("mouse2");
Cat cat = new Cat();
cat.action += mouse1.Run;
cat.action += mouse1.Jump;
cat.action += mouse2.Run;
cat.action += mouse1.Jump;
cat.Shout();
//cat.action(); //使用事件时,无法在类外调用委托。
}
}
}

C#委托全解析的更多相关文章

  1. Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能

    我们的Glide系列文章终于要进入收尾篇了.从我开始写这个系列的第一篇文章时,我就知道这会是一个很长的系列,只是没有想到竟然会写这么久. 在前面的六篇文章中,我们对Glide的方方面面都进行了学习,包 ...

  2. Google Maps地图投影全解析(3):WKT形式表示

    update20090601:EPSG对该投影的编号设定为EPSG:3857,对应的WKT也发生了变化,下文不再修改,相对来说格式都是那样,可以到http://www.epsg-registry.or ...

  3. C#系统缓存全解析(转载)

    C#系统缓存全解析 对各种缓存的应用场景和方法做了很详尽的解读,这里推荐一下 转载地址:http://blog.csdn.net/wyxhd2008/article/details/8076105

  4. 【凯子哥带你学Framework】Activity界面显示全解析

    前几天凯子哥写的Framework层的解析文章<Activity启动过程全解析>,反响还不错,这说明“写让大家都能看懂的Framework解析文章”的思想是基本正确的. 我个人觉得,深入分 ...

  5. iOS Storyboard全解析

    来源:http://iaiai.iteye.com/blog/1493956 Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果, ...

  6. 【转载】Fragment 全解析(1):那些年踩过的坑

    http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...

  7. (转)ASP.NET缓存全解析6:数据库缓存依赖

    ASP.NET缓存全解析文章索引 ASP.NET缓存全解析1:缓存的概述 ASP.NET缓存全解析2:页面输出缓存 ASP.NET缓存全解析3:页面局部缓存 ASP.NET缓存全解析4:应用程序数据缓 ...

  8. jQuery&nbsp;Ajax&nbsp;实例&nbsp;全解析

    jQuery Ajax 实例 全解析 jQuery确实是一个挺好的轻量级的JS框架,能帮助我们快速的开发JS应用,并在一定程度上改变了我们写JavaScript代码的习惯. 废话少说,直接进入正题,我 ...

  9. ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8,A9,A12,A15到Cortex-A53,A57

    转自: ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8,A9,A12,A15到Cortex-A53,A57 前不久ARM正式宣布推出新款ARMv8架构的Cortex-A50处理器系列 ...

随机推荐

  1. Queue 先进先出队列的操作

    1.Queue定义 System.Collections.Queue类表示对象的先进先出集合,存储在 Queue(队列) 中的对象在一端插入,从另一端移除. 2.优点 1.能对集合进行顺序处理(先进先 ...

  2. 整合Servlet到Spring容器

    有时在Spring(3.2.5)项目中,如果使用到Servlet,可能希望Servlet实例作为bean受Spring容器管理,这样也能自动注入其他需要的bean,查了下,发现只针对过滤器提供了代理类 ...

  3. hibernate-criteria查询

    Criteria查询是Hibernate提供的一种查询方式 下面就一个员工和部门来列一个总体的例子 package Test; import java.util.ArrayList; import j ...

  4. bootstrap学习总结-03 常用标签1

    1 显示段落 在HTML中,段落使用p标签包起来,重要的文字使用strong标签,em标签.<em> 标签告诉浏览器把其中的文本表示为强调的内容.对于所有浏览器来说,这意味着要把这段文字用 ...

  5. python 培训之HTTP

    1. urllib #!/usr/env/python # -*- coding:UTF-8 -*- from __future__ import print_function import sys ...

  6. FIFA halts 2026 bids amid scandal 国际足联在丑闻期间停止2026年足球世界杯申请

    FIFA halts 2026 bids amid scandal 国际足联在丑闻期间停止2026年足球世界杯申请 But official insists 2018 Cup will stay in ...

  7. MVC Autofac构造函数注入

    建立 空的 MVC4项目 首先引用 NuGet 里 autofac 和 autofac .integration. mvc 然后 建立Model public class Person { publi ...

  8. 将一个tabel加到另一个table

    DataTable rate = GetRate(str_catchType,); dt.Merge(rate);//将两个table合并

  9. ubuntu 重启 nginx 失败,* Restarting nginx nginx ...fail!

    ubuntu 重启 nginx 失败,* Restarting nginx nginx ...fail!       执行 nginx 重启服务时,提示失败如下: $ sudo service ngi ...

  10. 一个有趣的模拟光照的shader

    一个有趣的模拟光照的shader(类似法线贴图) http://www.cnblogs.com/flytrace/p/3395911.html -----  可否用于需UI中需要加灯的模型.