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自己,不能赋值。事件只能+=、-=,不能=、不能外部触发事件。

C#基础精华07(委托事件,委托的使用,匿名方法)的更多相关文章

  1. 委托学习过程及委托、Lambda表达式和匿名方法的关系总结及事件总结

    第一章,当开始学习委托的时候,我们会问什么是委托?为什么要学习委托? 一,什么是委托? 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法, ...

  2. 泛型委托及委托中所涉及到匿名方法、Lambda表达式

    泛型委托及委托中所涉及到匿名方法.Lambda表达式 引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到 ...

  3. 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式

    引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录 ...

  4. 关于委托:异常{ 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型 }

    转自:http://www.cnblogs.com/xiaofei59/archive/2010/11/25/1887285.html 异常{ 无法将 匿名方法 转换为类型“System.Delega ...

  5. 关于委托:异常{ 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型 }

    异常{ 无法将 匿名方法 转换为类型"System.Delegate",因为它不是委托类型 } 委托实际上是把方法名作为参数,但是若有好多个方法时,就要指明是哪个参数  查看如下代 ...

  6. c#基础精华01(强调代码规范,虚方法,抽象方法,接口)

    强调代码规范 规则(法律,必须遵守否则报错) 语法 规范(道德,大家都喜欢有道德的人.) 注释//,/**/,/// 骆驼命名 :第一个单词首字母小写,之后的单词首字母大写 userName.user ...

  7. .NET基础拾遗(4)委托和事件1

    一.委托初窥:一个拥有方法的对象 (1)本质:持有一个或多个方法的对象:委托和典型的对象不同,执行委托实际上是执行它所“持有”的方法. (2)如何使用委托? ①声明委托类型(delegate关键字) ...

  8. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

  9. jQuery代码优化:事件委托篇

    推荐阅读原文:http://www.ituring.com.cn/article/467# 推荐11收藏 随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面.jQuery为绑 ...

随机推荐

  1. 《JSON必知必会》

    每天上下班在地铁上很适合看这种书,入门级.难点不多.简约不失严谨. 自从全面转向ASP.NET MVC,现在基本上每天都和JSON打交道,效率.习惯.速度都要掌握. 这本书读起来很快,所以读完也蛮有成 ...

  2. 3月3日(3) Binary Tree Preorder Traversal

    原题 Binary Tree Preorder Traversal 没什么好说的... 二叉树的前序遍历,当然如果我一样忘记了什么是前序遍历的..  啊啊.. 总之,前序.中序.后序,是按照根的位置来 ...

  3. 【转】JavaScript中undefined与null的区别

    通常情况下, 当我们试图访问某个不存在的或者没有赋值的变量时,就会得到一个undefined值.Javascript会自动将声明是没有进行初始化的变量设为undifined. 如果一个变量根本不存在会 ...

  4. 2014-10 u-boot make过程分析

    /** ****************************************************************************** * @author    Maox ...

  5. 条形码Code128源代码

    public class Code128 { private DataTable m_Code128 = new DataTable(); ; /// <summary> /// 高度 / ...

  6. CentOs7&zookeeper

    下载安装包 wget http://www.apache.dataguru.cn/zookeeper/stable/zookeeper-3.4.6.tar.gz 解压 tar xzvf zookeep ...

  7. 重写session

    <?php ini_set('session.use_only_cookies', 0); $session_id = rand(10000, 99999); session_set_cooki ...

  8. 手写一个自己的简单MVC框架myPHP

    myPHP框架 采用的是MVC 思想,应用纯面向对象及项目单一入口,实现的一个自定义的框架.(自己兴趣的练习) 一.项目单一入口 入口文件 myphp\index.php前台 一个网站所有的请求都请求 ...

  9. PHP 跨域写cookie

    实际工作中,类似这样的要求很多,比如说,我们有两个域名,我们想实现在一个域名登录后,能自动完成另一个域名的登录,也就是PASSPORT的功能. 我只写一个大概,为了测试的方便,先编辑hosts文件,加 ...

  10. (转载)总结一下SQL语句中引号(')、quotedstr()、('')、format()在SQL语句中的用法

    总结一下SQL语句中引号(').quotedstr().('').format()在SQL语句中的用法 总结一下SQL语句中引号(').quotedstr().('').format()在SQL语句中 ...