委托可用来解耦以及状态变化的实时通知,以及其他的一些作用,但是经验所限,目前还未遇见。网上的大多数例子都是类似于,使用委托,然后用console返回方法的返回值,有时候会在想,委托的通知如果是这样的话,那么我可以用return以及out或者ref等就可以获得方法的返回值,其实也没错,但是要注意return一用上,就等于将return下面的代码全部停止运行,out与ref也是要在方法运行完了之后才会返回值,也就是说,我如果需要在方法运行中返回值的话,以上三个是无法做到的,但是委托就可以,因为委托是以方法为参数的,调用委托就是在执行委托所指向的方法,状态信息的处理可以再改方法内进行,但这种行为也可以直接在方法中就行调用另外一个方法来解决,效果是一样的,但是耦合度上就会有差别,当然还有其他的作用,我还没接触到,就不发声了。

使用委托需先使用delegate关键字定义,之后需实例化和声明,实例声明是需要注意,方法和委托的返回值和参数类型和个数需要一致才行,例:

public dalegate void DelegateTest(int x,int y);

main(){

DalegateTest dt=new DalegateTest(DelegateMethod);

dt();//或者dt.Invoke();

}

public static void DelegateMethod(int a,int b)

{

console.writeline(a+b);

}

C#中还有一个方法组转换的简便方法,这个方法允许开发者在调用以委托为参数的方法时,直接写入方法名,而不需要创建一个委托对象,例:

static void Main(string[] args)
        {
            SimpaleDelegate s = new SimpaleDelegate();

SimpaleDelegate.Handlers h = new SimpaleDelegate.Handlers(s.sub);
            s.Register(new SimpaleDelegate.Handlers(new SimpaleDelegate().sub));//原始写法
            s.Register(new SimpaleDelegate().Add);//方法组转换

s.Register(h);
            s.result3();
            s.RemoveRegister(h);
            s.result3();
            Console.ReadKey();
        }

namespace Delegate
{
   public class SimpaleDelegate
    {

//定义一个委托
        public delegate int Handlers(int x, int y);

//声明一个委托变量
        private Handlers handlers;

//注册一个委托
        public void Register(Handlers h)
        {
            handlers += h;
        }

//注销一个委托
        public void RemoveRegister(Handlers h)
        {
            handlers -= h;
        }
        public int Add(int a,int b)
        {
            Console.WriteLine("this is Add:{0}",a + b);
           return 0;
        }
       public void result3()
        {
           Console.WriteLine(handlers(2, 5));
        }
    }
}
例中的+=和-=就是委托中的多路广播的简写方式,在使用-=时要注意,要先创建委托对象,并保存在本地,在注销的时候要调用本地保存的对象,如若不然,将无法完成预期中的注销,即将sub注销。

同时需要注意到我在类中定义了一个私有的委托变量,为什么不是公有的呢?原因在于若是定义为公有的,调用者就可以直接访问委托,对委托变量重新赋值,这样的话就等于删除了当前所要调用的方法列表。

委托中还有一类泛型委托,类似public delegate void GenericDelegate<T>(T tag);这是定义了一个无返回值的,仅有一个参数的委托,在使用它的时候记得要注明类型名称,如:GenericDelegate<int> GD=new  GenericDelegate<int>(className);

上面说过,使用一个委托,我们需要先定义,在声明,但是这样通常会构成大量的只适用于当前项目的自定义委托,大部分时候我们都只是需要接受一组数据并返回一个值的委托,因此微软给我们内置了Action<>与Func<>,两者都可以指向多至16个参数的方法,区别在于Action<>返回void,Func<>的返回值的类型由Func的最后一个类型参数决定。

前面说了把委托定义为公有的坏处,这个坏处在事件中是不存在的,事件就是利用event关键字定义委托对象:public delegate void delegateName();public event delegateName eventName; ,这是定义,编译器在处理event关键字时会自动提供注册和注销以及任何必要的委托类型成员,这些委托成员变量总是声明为私有的,且声明必然只能在类的级别出现,且不可用static修饰,因此触发事件无法直接调用他们。这样说起来,事件就像是加了盔甲的委托一样。还可以使用EventHandler<T>来定义事件,类似,大部分的用法也与委托差不多,还记得前面说过,多路广播就是使用+=或者-=添加或者移除委托,例:eventName+=委托对象,这也是事件的调用方法,不过符号的左边是事件的名称,符号的右边是委托。同时因为方法组转换的存在,在符号左边也可直接写上符合事件规则的方法名称,例:eventName+=方法名称。

微软推荐的事件模式是类似public static void Name(object sender,EventArgs e);sender是对当前对象的一个引用,若是要传回数据,则需要自己重新定义一个EventArgs类型的实例,例:

public class CarEventArgs:EventArgs

{

public readonly string msg;//readonly为只读字段,只能在运行初始进行赋值,之后都无法进行修改,因而需在构造函数内进行赋值

public CarEventArgs(string message)

{

msg=message;

}

}

当调用者调用一个事件时,往往需要定义一个唯一的与相关联委托签名匹配的方法,但是这个方法很少被委托以为的任何程序调用,如此看来,手工定义一个由委托对象调用的方法就有点浪费,于是,我们可以这样做:

eventName+=delegate{//这里面是委托对象调用的方法内容};,这是一个不带参数的,带参数的是:eventName+=delegate(参数类型 参数{,...}){//这里面是委托对象调用的方法内容};,这样写就不用再去定义特定的处理程序,这叫做匿名方法。匿名方法不能访问定义它们的方法的ref和out参数,匿名方法中的变量不能与外部方法的变量重名。这时就要说说lambda表达式了,它是匿名方法更简单的写法,使用"=>"符号,例:

namespace Lambda
{
   public class Program
    {
        static void Main(string[] args)
        {
            EventClass e = new EventClass();
            e.SetMathHandler((string msg, int result) => { Console.WriteLine("Message:{0},Result:{1}", msg, result); });
            e.eventName += () => { Console.WriteLine("this is lambda"); };//这是供事件调用的代码
            e.Add(10, 10);
           
            Console.ReadLine();
        }
    }
}

namespace Lambda
{
   public class EventClass
    {
        public delegate void DelegateName();
        public event DelegateName eventName;
        public delegate void MathMessage(string msg, int result);
        private MathMessage mmDelegate;
        public void SetMathHandler(MathMessage taget)
        {
            mmDelegate = taget;
        }
        public void Add(int x,int y)
        {
            if (mmDelegate != null)
                mmDelegate.Invoke("Add", x + y);
            eventName();
        }
    }
}
结果是:

简单翻译(string msg, int result) => { Console.WriteLine("Message:{0},Result:{1}", msg, result);的意思就是,参数msg和result会被表达式console处理。

《精通C#》委托与事件(10章)的更多相关文章

  1. 第一章、C#委托和事件(Delegate、Event、EventHandler、EventArgs)

    第一章.C#委托和事件(Delegate.Event.EventHandler.EventArgs) 分类: 学习笔记-C#网络编程2012-12-08 14:10 7417人阅读 评论(3) 收藏  ...

  2. C#高级编程 (第六版) 学习 第七章:委托和事件

    第七章 委托和事件 回调(callback)函数是Windows编程的一个重要方面,实际上是方法调用的指针,也称为函数指针. .Net以委托的形式实现了函数指针的概念,.Net的委托是类型安全的. 委 ...

  3. 《C#从现象到本质》读书笔记(六)第8章委托和事件

    <C#从现象到本质>读书笔记(六)第二部分 C#特性 第8章委托和事件 从这一部分开始,知识点就相对少了,重要的是代码练习.奈何太高深的代码平常不怎么用,这些特性也不是经常写代码的. 委托 ...

  4. .NET面试题系列[7] - 委托与事件

    委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...

  5. [转载]C#深入分析委托与事件

    原文出处: 作者:风尘浪子 原文链接:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 同类链接:http://www.c ...

  6. [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)

    原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...

  7. C#综合揭秘——深入分析委托与事件

    http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C ...

  8. C#--深入分析委托与事件

    本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单. 还将为您解释委托的协变与逆变,以及如何使用 Delegate ...

  9. C# 语言规范_版本5.0 (第10章 类)

    1. 类 类是一种数据结构,它可以包含数据成员(常量和字段).函数成员(方法.属性.事件.索引器.运算符.实例构造函数.静态构造函数和析构函数)以及嵌套类型.类类型支持继承,继承是一种机制,它使派生类 ...

  10. [ASP.NET 大牛之路]02 - C#高级知识点概要(1) - 委托和事件

    在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...

随机推荐

  1. PL/SQL Developer连接Oracle 11g在Win8 64位系统下乱码

    PL/SQL Developer在64位系统上连接Oracle,需要安装32位Oracle client客户端,使用后,发现操作数据库出现乱码的情况.经过查找资料,解决此问题,方法如下: 需要在系统的 ...

  2. 解决windows 10无法打开.hlp帮助文件的问题

    最近学习UML,使用的Rational Rose 7.0,使用帮助时,才发现windows 10无法打开.hlp的帮助文件.虽然win10默认定向到微软支持页面,但发现通过下载补丁来查看hlp文件,实 ...

  3. 类ExampleA继承Exception,类ExampleB继承ExampleA。 有如下代码片断:

    try { throw new ExampleB("b") } catch(ExampleA e){ System.out.println("ExampleA" ...

  4. C++中的4个类型转换关键字

    转载:http://poplars.blog.163.com/blog/static/1394221742013021111210567/ n多书里面推荐要养成使用转型关键字的习惯,几年过去了,感觉还 ...

  5. mybatis使用generator生成对应的model、mapping配置文件、dao

    http://blog.csdn.net/fengshizty/article/details/43086833 使用时 补充 输入命令:cd d:\generator  敲回车 再输入命令:d: 敲 ...

  6. 利用JavaScript来实现用动态检验密码强度

    平时我们会在某些网站的注册页面或者更改密码的页面发现当我们输入密码时,会有一个类似于进度条的长条进行提示用户输入的密码强度.如下图: 我看到有些人用几张不同的图片来替换,这样似乎可以,但是不太好.所以 ...

  7. [Linux] Nginx networking 403 Forbidden 静态文件不允许查看

    nginx 的 403 Forbidden errors 表示你在请求一个资源文件但是nginx不允许你查看. 403 Forbidden 只是一个HTTP状态码,像404,200一样不是技术上的错误 ...

  8. 【Treap】bzoj1588-HNOI2002营业额统计

    一.题目 Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司 ...

  9. linux下的a.out文件

       当然这里,我更重要的是强调这个什么段,什么段.这以前就知道.但其实是对一个可以执行的c语言程序的分析.就好比你分析一篇作文.有标题.有段落. .out文件就是扩展名为out的文件,它本身不代表任 ...

  10. win7的HOST文件夹具体位置

    win7的HOST文件位置为C:\WINDOWS\system32\drivers\etc\文件夹下,快捷查看方法如下: 1.按win+r,输入C:\WINDOWS\system32\drivers\ ...