委托可用来解耦以及状态变化的实时通知,以及其他的一些作用,但是经验所限,目前还未遇见。网上的大多数例子都是类似于,使用委托,然后用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. [转]Linux进程间通信——使用消息队列

    点击此处阅读原文 另收藏作者ljianhui的专栏初学Linux 下面来说说如何使用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linu ...

  2. xml 的 CDATA

    <PolicyURL><![CDATA[http://ectp.tpi.cntaiping.com/TPEBizWeb/pages/B2C/show/downLoad.do?poli ...

  3. 使用js倒计时还有几天及计时过了几天

    公司主营业务是体育赛事为主的:尤其是足球赛事.现正值2016法国欧洲杯:之前忙于做欧洲杯专题没时间总结.现分享一个工作中需求带来的经历. 需求是:从现在开始倒计时欧洲杯还有多久开赛:当开赛之后开始计算 ...

  4. HTML纯javaScript代码写图片轮播

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. ORACLE表的恢复

         对误删的表,只要没有使用PURGE永久删除选项,那么从flash back区恢复回来希望是挺大的.一般步骤有: 1.从flash back里查询被删除的表     select * from ...

  6. 我的Android第三章

    先看效果图. 点击之后出变成 按钮内容改变了,并且弹出一个小提示 下面我们就来看看如何实现这个小案例 1)先打开string.xml文件,把要定义的字符串资源放置在里面 2)然后我们要画页面,基本An ...

  7. bzoj1080

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1080 神暴力,待搞懂. 代码 #include <cstdio> #includ ...

  8. Android 本地/网路下载图片实现放大缩小

     Android 本地加载/网路下载图片实现放大缩小拖拉效果,自定义控件. package com.example.ImageViewCustom; import android.app.Activi ...

  9. angular的双向数据绑定

    方向1:模型数据(model) 绑定 到视图(view) 实现方法1:{{model变量名}} $scope.num=10 <p>{{num}}</p> 实现方法2: 常用指令 ...

  10. EF CodeFirst 关系配置

    自从开始学习asp.net mvc采用code first以来,关系配置就没有搞清楚过!(⊙﹏⊙)b 笔记之前先感谢以下文章和博主,对他们表示崇拜,由浅入深.举例恰当.拨云见日.茅塞顿开,还有什么词, ...