1.委托概述

委托是一种数据类型,像类一样(可以声明委托类型变量)。方法参数可以是int、string、类类型

void M1(int n){  } √

void M2(string s){  } √

void M3(Person p){  } √

委托就是一种数据类型,用来存放方法的数据类型。

那么委托到底把方法存到哪里了?其实委托还是一个类。把方法包装成了一个委托。

方法是不能直接赋值的,那么能不能声明一个能存放方法的变量呢(委托)。像存储变量一样把方法存储起来。

2.委托的使用

声明委托的方式:delegate 返回值类型 委托类型名(参数) 比如delegate void StringProcess(string s); 注意这里的除了前面的delegate,剩下部分和声明一个函数一样,但是StringProcess不是函数名,而是委托类型名

存储什么样的方法就声明什么类型(方法参数与返回值)的委托。

声明的委托是一种类型,就像int、Person一样,如果要用的话还要声明委托类型的变量,声明委托类型变量的方式:StringProcess f1;

将委托类型变量指向函数 StringProcess sp = new StringProcess(SayHello),这样就可以像调用普通函数一样把sp当成函数用了。委托可以看做是函数的指针。整数可以用整数变量指向它,对象可以用对象变量指向它,函数也可以用委托变量指向它。和直接调用函数的区别:用委托就可以指向任意的函数,哪怕是之前没定义的都可以,而不使用受限于那几种。

将委托类型变量指向函数还可以简化成StringProcess sp = SayHello,编译器帮我们进行了new。但是不能sp=PrintIt(),因为这样就成了函数调用。

3.委托用例

 class Program
{
//定义一个委托类型DelegateString
public delegate string DelegateString(string text);
//定义一个ChangeString类
public class ChangeString
{
//定义一个ChangeStringText方法,包含一个字符串数组和一个委托变量
//ChangeText用来接收传进来的方法
public void ChangeStringText(string[] names,DelegateString ChangeText)
{
for (int i = ; i < names.Length; i++)
{
//调用传进来的方法改变字符串
names[i] = ChangeText(names[i]);
}
}
}
static void Main(string[] args)
{
ChangeString cs=new ChangeString();
string[] names = {"卡卡西","佐助","鸣人"};
//调用ChangeStringText方法,把names数组和JoinString方法传进去
cs.ChangeStringText(names, JoinString);
//遍历输出改变后的数组
for (int i = ; i < names.Length; i++)
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
//定义一个NewString方法
public static string NewString(string name)
{
return "----"+name+"----";
}
//定义一个JoinString
public static string JoinString(string name)
{
return "★" + name + "★";
}
}

4.运行结果

传入NewString方法


传入JoinString方法

匿名方法

使用Delegate的时候很多时候没必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这时候使用匿名方法最合适。
匿名方法就是没有名字的方法。3就是没有名字的int对象。3+5就是两个匿名int对象的相加,允许匿名对象,就允许匿名方法。
 ProcessWordDelegate p = delegate(string s)
            {
                Console.WriteLine(s);
            };
知道C#中有匿名方法,看到这种写法知道是匿名函数即可。
匿名方法与lambda表达式最终编译为一个方法。

MyDelete md = delegate() { Console.WriteLine("嘎嘎"); };
md();

================================================================
 public delegate void SayDelegate();
    SayDelegate say = () => { Console.WriteLine("hhh"); };
public delegate int MyDelete2(int num);
MyDelete2 md2 = delegate(int number) { return number + 10; };
            int result= md2(20);
            Console.WriteLine(result);
            Console.ReadKey();
================================================================
 public  delegate  string SayDelegate(string n);
    SayDelegate say = x => x+"好帅";
            Console.WriteLine(say("小杨"));
===============================================================
 T1((x, y, z) => x - y + z);
        public static void T1(SayDelegate say)
        {
            int result = say(10, 20, 30);
            Console.WriteLine(result);
        }
 public delegate int SayDelegate(int n1, int n2, int n3);
===============================================================
 List<int> list = new List<int>() { 1,2,3,4,5,6,7,8,9};
            IEnumerable ieor= list.Where(x=>x>5);
            foreach (int item in ieor)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
==============================================================

多播委托*(委托链,委托的组合)

delegate void ProcessWordDelegate(string s)
ProcessWordDelegate d = new ProcessWordDelegate(SayHello)+new ProcessWordDelegate(ToLower)
多播委托如何处理返回值?
委托绑定多个方法后,其中一个方法执行发生异常后面的方法还会继续执行吗?不会!
一个重要的方法GetInvocationList();//返回一个Delegate[]类型。Delegate类是一个抽象类,是所有委托的父类。
组合的委托必须是同一个类型
相当于创建了一个按照组合的顺序依次调用的新委托对象。
委托的组合一般是给事件用的,用普通的委托的时候很少用

为委托的增减方法

d+=SayHello,为委托增加一个方法,不要感觉奇怪,因为它就是d=d+ SayHello
d-=SayHello,将方法从委托中移除。
Delegate.Combine();

委托的一些应用:
凡是需要回调的地方都能用到委托。
自定义类(控件、通信类……(事件))
多线程
窗体之间回传值
正则表达式中替换Email掩码Replace()

委托的本质1(*)

其实就是一个类把方法包装了一下,委托都继承自System.MulticastDelegate,而System.MulticastDelegate又继承自System.Delegate
多播委托就是有一个委托数组,依次调用。

class Program
    {
        static void Main(string[] args)
        {
            UpdateDelegate upde = M1;
            upde += M2;
            upde += M3;
            upde -= M2;
            upde = M4;
            upde();
            Console.ReadKey();  
  //输出 M1 M2 M3 M4 
        }
        public static void M1()
        {
            Console.WriteLine("M1");
        }
        public static void M2()
        {
            Console.WriteLine("M2");
        }
        public static void M3()
        {
            Console.WriteLine("M3");
        }
        public static void M4()
        {
            Console.WriteLine("M4");
        }
    }
    public delegate void UpdateDelegate();

===================================================================
ResultDelegate M1 = T1;
            M1 += T2;
            M1 += T3;
            M1 += T4;
            int r = M1();
            Console.WriteLine(r);
            Console.ReadKey();     //输出M4
 public static int T1()
        {
            return 1;
        }
        public static int T2()
        {
            return 2;
        }
        public static int T3()
        {
            return 3;
        }
        public static int T4()
        {
            return 4;
        }
public delegate int ResultDelegate();
===========================================================
 Delegate[]des=  M1.GetInvocationList();
          foreach (Delegate item in des)
          {
              ResultDelegate res = item as ResultDelegate;
              Console.WriteLine(res());
          }
=============================================================单独拿到里面每个方法

事件(通过委托实现的,委托才是事件能正常执行的核心内容)

事件语法:event ProcessWordDelegate 例子 OnInt
加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。在IntUC类外部就不能通过OnInt(3)的方式调用注册的委托了。只能+=、-=!

事件本质论

event会自动生成一个private delegate变量和两个函数: add和remove,C#编译器用这两个方法支持+=和-=操作符 (*)。C#<>.Net。
public event MyDelegate OnEvent;
内部实现是(示例性)
private MyDelegate OnEvent;
public void Add(MyDelegate d)
{
   OnEvent+=d;
}
public void Remove(MyDelegate d)
{
   OnEvent-=d;
}
因为OnEvent是private的,所以在类外部不能OnEvent(1)触发事件,但是在类内部可以。
public的方法只有Add和Remove,所以只能+=、-=,其他的操作都是不可以的。

委托和事件的区别(常考)

委托和事件没有可比性,因为委托是数据类型,事件是对象(可以理解为对委托变量的封装。),下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别。事件的内部是用委托实现的。(举例子:三种实现事件方式的区别(直接用委托实现、用私有委托+公有方法模拟事件,直接用event事件实现))
因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。add、remove。
事件是用来阉割委托实例的。事件只能add、remove自己,不能赋值。事件只能+=、-=,不能=、不能外部触发事件。

最新文章

  1. [资料分享]Java35期基础班和就业班
  2. CSS高效开发实战:CSS 3、LESS、SASS、Bootstrap、Foundation --读书笔记(2)CSS3利用图层叠加实现多背景
  3. MySQL 5.6 &amp; 5.7最优配置模板
  4. windows下安装memcache的基本步骤
  5. 一个很不错的适合PHPER们书单,推荐给大家【转】
  6. 如何重置CentOS/RHEL 7中遗忘的根用户帐户密码
  7. dede cms列表页调用文章简介(借鉴)
  8. Java基础 —— CSS
  9. TortoiseGit安装和使用的图文教程
  10. 用Python写的批量文件重命名
  11. [三]SpringMvc学习-封装、乱码问题、重定向、转发
  12. 安装 SQL Server 2008 R2 的硬件和软件要求(转)
  13. C# - 重定义一个接口的实现
  14. 小程序 canvas画本 地图片
  15. 用Jdbc连接数据库后实现增删改查功能
  16. 操作系统学习笔记(二) 页式映射及windbg验证方式
  17. dhtmlxTreeGrid
  18. windowsAPI之OpenProcessToken,AdjustTokenPrivileges 和LookupPrivilegeValue&lt;转&gt;
  19. mvc 封装控件使用mvcpager
  20. POJ1220 Number Base Conversion

热门文章

  1. MySQL数据库的登陆
  2. CSS样式三
  3. Java WebService简单实例
  4. 暑假集训(5)第一弹——— Super Jumping! Jumping! Jumping!(hdu1087)
  5. putty 实现不用输入用户名密码直接登陆
  6. Qt5中使用lambda表达式
  7. 操作xml文档的常用方式
  8. 禁止指定目录执行php文件
  9. ecshop订单中配送方式报错
  10. Python 信号量