委托可用来解耦以及状态变化的实时通知,以及其他的一些作用,但是经验所限,目前还未遇见。网上的大多数例子都是类似于,使用委托,然后用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. Interpolation particles In Katana

    I write the sphere radius interpolation for katana plugin that can transfer attributes,render attrib ...

  2. java 使用jar包

    //主类 路径 /home/fly/flywww/c/java import mypackage.One; import mypackage.Two; public class Test { publ ...

  3. Icon字体制作

    工具网站:https://icomoon.io 这个网站是免费的 功能也很强大 不过我那是铁通网络,导致这个网站不能访问,做vpn跳转就可以了 正题: 点击这里进入制作页面: 点击这里选取 svg 矢 ...

  4. delphi XE 5 Android 真机调试简易安装教程

    ① FireMonkey[DELPHI XE5]QQ群号:165232328,群内超过1600移动开发爱好者 第一步,打开手机中的USB调试 电脑自动装驱动,但是找不到 去手机官网下载驱动 手动安装驱 ...

  5. 新版macbook air OS X El Capitan 10.11安装WIN找不到驱动介质???

    这个问题已经解决 首先进入Boot Camp6 以后 顶上会有一个操作 -下载windowns 驱动程序 保存在优盘里面.然后再分区选择ISO(中间和你前面做的一样)电脑重启进入WIN安装 到你们出现 ...

  6. 零配置简单搭建SpringMVC 项目

    SpringMVC是比较常用的JavaWeb框架,非常轻便强悍,能简化Web开发,大大提高开发效率,在各种Web程序中广泛应用.本文采用Java Config的方式搭建SpringMVC项目,并对Sp ...

  7. mysql导入乱码问题,centOS

    CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;mysql -uroot -p --default ...

  8. Java-坦克大战

    利用Java语言中的集合.Swing.线程等知识点编写一个坦克大战游戏.(1) 画出敌我坦克的原理:在坦克类里面有一个布尔类型变量good.用于判断坦克的阵营,在创建坦克对象时在Tank类的构造方法中 ...

  9. My first python script for work

    I write it yesterday to watch the NE process(rcpfd,cfgd) automatically, then i will write a window t ...

  10. c++左值和右值

    c++编程中如果出现把一个函数的返回值.强行转化后的对象 作为函数的参数传进去时,编译器会报错的情况.这时候就该注意了,你需要把该函数的参数类型前加上const修饰. 原因在于c++的左值和右值有所区 ...