从大学就开始做C#这块,也做C#几年了,最近又从ios转回.Net,继续做C#,之前也没有写博客的习惯,写博客也是从我做ios的时候开始的,现在既然又做回了.net,那就写点关于.Net的博客,可能在大牛眼里这些都是简单基础的,不过回过头看我当时初学的时候觉得委托事件是不容易理解的,我这里也是想着联系着OC,两者有比较的学习下。毕竟都是面向对象语言,思想是相通的。

委托在OC中类似block,都是指向一个函数,其实他没和C++的函数指针类似。但委托还是和函数指针不太一样,委托是完全面向对象的,是类型安全可靠的。C++的指针仅仅指向成员函数,而委托同时封装了一个对象实例和方法。

委托声明用于定义一个从System.Delegate类派生的类。

格式:属性集 修饰符 delegate 返回值类型(A) 标识符(C)(形参列表(B));

一、委托是什么?

看上面的红字我们可以明白其实委托是一个类。其实类是什么?类也是一种数据类型,它了String类一样,也是一个数据类型,所以呢委托其实也是一个数据类型,只是这个数据类型和其他的有点不同,它这个数据类型指向的是一个函数。一个返回值为A,形参列表为B的名为标识符C的函数。其实这和OC中的block类似,block中也是用来定义函数。我们用typedef  void(^myblock1)(int a,int b);来定义一个block,其实就是定义一个数据类型。上面的委托声明也是定义了一个引用类型的数据类型。

二、委托怎么用?

上面也说了,声明一个委托其实就是声明了一个数据类型,和Person、String一样都是一个数据类型。我们在使用委托和使用Person、String类型的数据一样。也是先声明:public 类型(Person、String) 变量(或属性)名。所以我们在使用委托时也是这样。只是这个变量或属性对应的是一个函数。

三、例子

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
//定义了一个从System.Delegate类派生的类
//也可以理解为一种数据类型 这种数据类型指向返回值为void 参数为Person对象的函数
//我们也可以把Person类理解为一种数据类型 只是它包含的是Name和Age
public delegate void EatFood(Person p); public class Person
{ public string Name { get; set; } public int Age { get; set; } public Person(string name, int age)
{
Name = name;
Age = age;
} //既然委托是一数据类型和String一样,所以可以像声明String对象一样声明代理变量
public EatFood eatFood; public void eating()
{
if (eatFood != null)
{
eatFood(this);
}
} }
}

上面定义了一个Person类,也定义了一个定义了一个从System.Delegate类派生的类EatFood,同时在Person类中声明了EatFood类类型的一个变量,在eating()函数中使用了这个变量。ps:请留意上面代码中的注释。下面的代码中我们定义了两个Person对象,一个chinesePerson一个englishPerson,而分别为两个类的eatFood变量指定不同的函数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
class Program
{
static void Main(string[] args)
{
Person chinesePerson = new Person("小明",);
//通过构造函数实例化对象
chinesePerson.eatFood = new EatFood(chineseEat);
chinesePerson.eating(); Console.WriteLine("--------------------------------------"); Person englishPerson = new Person("Ivan",);
//通过直接复制来实例化对象
englishPerson.eatFood = englishEat;
englishPerson.eating();
Console.ReadLine(); }
static void chineseEat(Person p)
{
Console.WriteLine("我是{0},我今年{1}岁了,我吃馒头",p.Name,p.Age);
}
static void englishEat(Person p)
{
Console.WriteLine("I'm {0},I am {1} , I eat MianBao",p.Name,p.Age);
}
} }

可以看到针对不同的对象指定不同的eatFood变量则执行的结果也不一样。

四、委托和其他数据类型的区别

上面也说了可以把委托当做是一个数据类型,但它和普通的数据类型还是有区别的。这可能就是现在的个性吧,委托也有委托的个性。

委托实例化用于创建委托实例,和类实例创建语法相同。但委托可以封装多个方法,这些方法的集合合称为调用列表。委托使用+、+=、-、-=运算符向调用列表中增加或删除方法。

我们对上面的代码稍作改动,Person类不用改,只改Main方法中的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
class Program
{
static void Main(string[] args)
{
Person chinesePerson = new Person("小明",);
//通过构造函数实例化对象
chinesePerson.eatFood = new EatFood(chineseEat);
chinesePerson.eatFood += englishEat;
chinesePerson.eating(); Console.WriteLine("--------------------------------------"); Person englishPerson = new Person("Ivan",);
//通过直接复制来实例化对象
englishPerson.eatFood = englishEat;
englishPerson.eatFood += chineseEat;
englishPerson.eating();
Console.ReadLine(); }
static void chineseEat(Person p)
{
Console.WriteLine("我是{0},我今年{1}岁了,我吃馒头",p.Name,p.Age);
}
static void englishEat(Person p)
{
Console.WriteLine("I'm {0},I am {1} , I eat MianBao",p.Name,p.Age);
}
} }

为了促进中西交流,好多人去留学也有好多来到中国的,所以在吃的方面彼此都会吃对方的。所以要增加方法来表示吃不同的食物。有了委托可以通过+=、-=来实现增加、删除调用列表,这样就方面很多。从下面的输出结果能看到,每个Person对象都调用了chineseEat、englishEat函数。

五、好处

上面的demo也展示了委托的使用方法,通过上面的使用我们可以思考下使用它的好处。我们如果不使用委托来实现这个功能的话,我们可能会在Person类中做一个判断,判断下是Chinses还是English,可是这样的话,如果哪天有了日本、法国等,那又要多好多个判断。可扩展性不好。可能有的会说可以在Person里面定义一个虚方法,分别声明Chinese、English类继承Person类重写虚方法,这确实是一个方法,如果有新的要扩展的话可以直接创建一个新的类重写虚方法就搞定了,不过这样的话如果只是这个方法不同,就要写一个类,这样未免杀鸡用牛刀了。所以说委托还是一个不错的选择。如果不仅要增加语言还要增加方法那这就更麻烦了。有了委托这些全解决。

六、事件

对象之间的交互是通过消息传递来实现的,而事件就是对象发送的消息,通过发信号的形式通知操作的发生。引发事件的对象为事件发送方,捕获事件并对其做出响应的对象为事件接收方。在事件通信中,事件发送方不知哪个对象或方法将接收它引发的事件,所需要的是在发送方和接收方之间用一个纽带来联系,在C#中使用委托为这个纽带。

事件声明的格式:属性集 修饰符 event 委托类型 事件名。

其实说白了就是事件是对委托变量的封装。请注意上面写的,我一直写的是委托类型的变量,面向对象的三大特征之一就是封装,例如变量和属性。在上面直接使用委托来指定函数,其实这和直接使用变量一样,但是在面向对象中一般不会直接访问变量,而是对变量进行封装,例如属性{get;set;}方法。事件是对委托的封装。我们来看一下事件的使用,和上面使用委托一样,我们在Person类中声明一个事件。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
//定义了一个从System.Delegate类派生的类
//也可以理解为一种数据类型 这种数据类型指向返回值为void 参数为Person对象的函数
//我们也可以把Person类理解为一种数据类型 只是它包含的是Name和Age
public delegate void EatFoodDelegate(Person p); public class Person
{ public string Name { get; set; } public int Age { get; set; } public Person(string name, int age)
{
Name = name;
Age = age;
} //既然委托是一数据类型和String一样,所以可以像声明String对象一样声明代理变量
//public EatFood eatFood;
//之前是直接声明委托,现在是声明一个事件
public event EatFoodDelegate EatFoodEventHandler; public void eating()
{ if (EatFoodEventHandler != null)
{
EatFoodEventHandler(this);
}
} }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Delegate
{
class Program
{
static void Main(string[] args)
{
Person chinesePerson = new Person("小明",);
//通过构造函数实例化对象
chinesePerson.EatFoodEventHandler += new EatFoodDelegate(chineseEat);
chinesePerson.EatFoodEventHandler += englishEat;
chinesePerson.eating(); Console.WriteLine("--------------------------------------"); Person englishPerson = new Person("Ivan", );
//在委托中 可以直接使用=来给委托对象复制 而在事件中就不能直接使用= 要使用+=
englishPerson.EatFoodEventHandler += new EatFoodDelegate(englishEat);
englishPerson.EatFoodEventHandler += chineseEat;
englishPerson.eating();
Console.ReadLine(); }
static void chineseEat(Person p)
{
Console.WriteLine("我是{0},我今年{1}岁了,我吃馒头",p.Name,p.Age);
}
static void englishEat(Person p)
{
Console.WriteLine("I'm {0},I am {1} , I eat MianBao",p.Name,p.Age);
}
} }

上面可以看到,使用事件来实现了同样的功能。

七、委托和代理设计模式的区别

不管是使用委托或者事件其实它们都是在A对象(本例中的Person对象)中调用B对象中的方法,这与设计模式中有相似之处。具体代理设计模式这里就省略了,委托和代理都是在A对象使用B对象中的方法。不过它们还是有区别的,委托中在A中直接使用的是B中的方法,是类与方法之间的,代理设计模式中是将A类中设置一个B类变量,然后通过B来使用B中的方法,是类与类之间的。这也是我的个人理解,不知道对不对,错了的话也希望大牛指正,以免耽误了其他的社会主义接班人。

C#语法之委托和事件的更多相关文章

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

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

  2. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

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

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

  4. C#委托与事件

    一.在控制台下使用委托和事件 我们都知道,C#中有"接口"这个概念,所谓的"接口"就是定义一套标准,然后由实现类来具体实现其中的方法,所以说"接口,是 ...

  5. .NET委托和事件

    .net学习之委托和事件   1.什么是委托 通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器 上传图片: 2.委托语法 准备一个方法:string Hello(string ...

  6. C# 关于委托和事件的妙文:通过一个例子详细介绍委托和事件的作用;Observer模式简介

    委托和事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见 ...

  7. C#知识体系(二)用案例来理解委托与事件

    上一篇博客讲到了LinQ和lambda的常用方法 还有很多我们未知但c#设计团队已经为我们封装好的类和方法.随着我们不断的熟悉C#语言,渐渐的就会接触到其他的知识点,委托.事件.反射.线程.同步,异步 ...

  8. C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命

    使用面向对象的思想 用c#控制台代码模拟猫抓老鼠 我们先来分析一下猫抓老鼠的过程 1.猫叫了 2.所有老鼠听到叫声,知道是哪只猫来了 3.老鼠们逃跑,边逃边喊:"xx猫来了,快跑啊!我是老鼠 ...

  9. 《C#图解教程》读书笔记之五:委托和事件

    本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.委托初窥:一个拥有方法的对象 (1)本质:持有一个或多个方法的对象:委托和典型的对象不同,执行委托实际上是执 ...

随机推荐

  1. django-ORM相关代码及其sql执行次数

    1.普通情况:通过log可以看出,这种情况下,访问了1次数据库 def test(request): """测试连表""" users = ...

  2. GPS欺骗(一)—无人机的劫持

    本文作者:唯念那抹瑞利蓝 今天我们所讲的是GPS欺骗的方式和简单的定义.让大家对GPS欺骗这个方面有所了解.GPS是全世界地一个卫星定位系统,由美国制造. 0×01 例子2011年伊朗劫持美国无人机 ...

  3. webpack快速入门——实战技巧:webpack优化黑技能

    1.抽离jquery,vue(多个第三方类库抽离) 修改入口文件(webpack.config.js中) entry: { entry: './src/entry.js', jquery:'jquer ...

  4. xp——极限编程的几个方法

    最近阅读<Head First Java>一书时,看到极限编程(XP)的概念,觉得很有趣,摘抄下来以备后期继续学习. 极限编程(XP)是一种新型的软件开发方法论.他的构想是结合了许多种&q ...

  5. Tomcat几种出错方法

    1.  Several ports (8005, 8089, 8009) required by Tomcat v8.0 Server at localhost are already in use. ...

  6. 清除float的方法

    清除浮动有两种方法: 一种是加入clear:both: 一种是BFC申明: <!doctype html><html><head><meta charset= ...

  7. Swinject 源码框架(二):循环依赖的解决

    可能存在循环依赖,比如 Parent 强制有 Child, Child 弱持有 Parent. 具体实现如下.Parent 初始化时,必须传入 Child,而 Child 初始化不必传入 Parent ...

  8. POJ 2291

    #include<iostream> #include<stdio.h> using namespace std; int compare(void const *,void ...

  9. h5移动端聊天室|仿微信界面聊天室|h5多人聊天室

    今年的FIFA世界杯甚是精彩,最近兴致高涨就利用HTML5开发了一个手机端仿微信界面聊天室,该h5聊天室采用750px全新伸缩flex布局,以及使用rem响应式配合fontsize.js,页面弹窗则是 ...

  10. IOC容器02

    获取xml文件路径,使用IO读取xml文件,使用Document对象解析xml文件,将xml中的bean的信息注册到BeanDefinition类,将BeanDefinition保存到一个map中:该 ...