美文网首页
C#——委托与事件系列一

C#——委托与事件系列一

作者: 一个有味道的名字 | 来源:发表于2017-03-30 16:06 被阅读505次

本来应该学习泛型与委托的,但是发现C#这里还没有系统的记录过委托与事件,所以先打算把委托与事件补上再继续泛型与委托的记录。
然后呢,今天如果没有意外的话unity方面也会记录一些关于编辑器扩展的笔记,还有一直想学习的C#socket(套接字)的笔记。
万事开头难,只要开了头,剩下的事就可以继续下去了。
关于委托与事件,前面其实也有记录到,但是那是关于在unity中使用委托与事件的一个小事例而已,这里主要是记录一下C#中关于委托与事件到底是讲的什么?如何使用?以及有什么坑需要注意。
我打算把这个写成一个系列,毕竟我也是边学边写,然后呢,后续也会再次写到如何将委托与事件运用到unity中。
还有就是,还会重新再学一下C#的设计模式,基础一定要打牢固。

OK,废话说完,开始进入正题:
首先什么是委托?委托,delegate,是表示对具有特定参数列表和返回类型的方法的引用的类型。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。(MSDN解释)
MSDN给出的解释说实话,很恶心,还绕口。
其实,在我看来,委托就是一种自定义的类型,就类似于一个class,然后我们可以通过这个类型来创建实例对象,这个实例对象,其实类似于引用类型的对象那样,存储的是一个“地址”,只不过这个地址指向的是函数方法,也就是说,委托实例就类似于C++中的函数指针那样。
委托是安全封装方法的类型,类似于C和C++中的函数指针,委托是面向对象的。类型安全的和可靠的。
总结: 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。
可能解释的还是很乱,不过没关系,有个了解,不需要死扣定义。

继续,来看一下委托的定义:public delegate void MyDelegate(string str);
注意,从这儿定义来看,其实委托的定义与一般方法的定义,只是多了一个delegate关键字而已。
解释一下整个定义的意思:
public就是访问权限,没有什么差别。
delegate 声明委托的关键字。
void,方法的返回值,如果你将某个方法绑定到委托上,那么该方法的返回值要与委托定义时的一致,在这里了都要是void。
MyDelegate,委托的名字,其实就是一个类名,我们可以使用它来创建我们的委托对象。(string str),方法参数,如果你将某个方法绑定到委托上,那么该方法的参数要与委托定义时的一致,在这里参数是一个string类型。
当我们声明一个委托后,在编译时,会自动生成一个委托类型,自动继承MulticastDelegate,而MulticastDelegate又是继承自Delegate类的。
注意:这里,我们声明的是一个委托,虽然看起来像是声明了一个方法,它没有具体的实现,因为它相当于一个类。

再次继续,如何使用委托?(先不要着急事件)
直接来看例子好了:
首先我在一个类中写了两个方法,一个实例方法,一个静态方法:
public class TestMethod{
public static void StaticMethod(string str)
{
Console.WriteLine("StaticMethod:"+str);
}
public void InstantMethod(String str)
{
Console.WriteLine("InstantMethod:"+str);
} }
然后在program类中使用这个类:

class Program
 {
     static void Main(string[] args){
         MyDelegate myDel;
         TestMethod testMethod = new TestMethod();
         myDel=testMethod.InstantMethod;
         myDel+=TestMethod.StaticMethod;
         myDel("AAA");
         myDel-=testMethod.InstantMethod;
         myDel("BBB");
     }
 public delegate void MyDelegate(string str);
 
 public class TestMethod
 {
    public static void StaticMethod(string str)
    {
        Console.WriteLine("StaticMethod:"+str);
    }

    public void InstantMethod(String str)
    {
          Console.WriteLine("InstantMethod:"+str);
    }
 }

}

结果会是什么?输出: 图片
但是,注意,如果我们直接:MyDelegate myDel = new MyDelegate();

这是会报错的,如下图:

2.png

是不是会想到构造函数,这个问题的解决方式,我是采用了,将委托的定义在封装一次,如下所示:

namespace class1
{
    class Program
    {
        static void Main(string[] args)
        {
            Method mt = new Method();
            Del del = new Del();
            del.myDel = mt.InstantMethod;
            del.myDel += Method.StaticMethod;
            Console.ReadKey();
        }
    }
    class Del
    {
        public MyDelegate myDel;

    }
    public delegate void MyDelegate(string str);

    class Method
    {
        public void InstantMethod(string str)
        {
            Console.WriteLine("InstantMethod" + str);
        }
        public static void StaticMethod(string str)
        {
            Console.WriteLine("StaticMethod" + str);
        }
    }
}

怎么说呢,就类似于一种曲线救国的样子,既然我不能new出来你,那么我就new出来封装你的类。然后用这个类的对象来调用你,大概就是这个意思。
甚至,我们可以对委托进行“加减运算”以及判断是否相等的逻辑判断(PS:其实就是增加方法与删除方法)
比如,我们来改一下Main函数里的代码:

3.png

我们来看看结果:

5.png

看到了没有,可以进行逻辑判断,当然,你可以自己去尝试一下减法的作用。

OK,关于委托的最最基础的知识点先整理到这里,还有一些关于匿名方法和Lambda表达式运用在委托中,会在下篇中记录。

那么现在开始记录一下关于事件的基础知识:
什么是事件呢?
老规矩,来看一下MSDN上的解释:
类或对象可以通过事件向其他类或对象通知发生的相关事情,发送事件的类称为“发行者”,接收事件的类称为“订户”。
解释的还算是清晰吧,不过可能对于一些新人来说还是一头雾水的样子。

那么开始事件的记录:我先说一句:事件是对委托的隐藏。(老规矩,不要试图去理解它,有个印象就可以了).
先来说一下,为什么需要事件?
面向对象三大特性:继承,封装,多态。其中封装就是指将某些我们不想让外部看到的东西包围起来,给外部留出来一个接口,可以使用就行,不让外部的人员对其进行改动,这是做使得代码更加的安全。
我们现在都知道了,委托其实就是一个类,那么对于其对象而言,访问权限肯定是该public的时候public,该private的时候private。
但是,当private的时候,我们就在客户端无法调用它了,也就是说它就没什么卵用了,那我们干嘛还声明它出来。
但是,当public的时候,又严重的破坏了封装性,我们可以随意的修改,这点后果也很严重。
如果是针对别的类型,比如string,int等等,那么我们可能就会想到用属性来对其进行封装。
于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
OK,来看一下事件的定义:我们将委托去事件放到同一个类中,并且给一个触发方法:

    class EventTest
    {
        public delegate void MethodHandler(string str);
        public event MethodHandler MethodEvent;
        
        public void Print(string str)
        {
            if (MethodEvent != null)
            {
                MethodEvent(str);
            }
        }
    }

看到了没有,public event MethodHandler MethodEvent;
这个事件的定义,其实就是比创建委托对象多了一个关键字event。
然后在Main函数中,我们这样写:

           EventTest ev = new EventTest();
            Method mt = new Method();
            ev.MethodEvent += mt.method;
            ev.MethodEvent += mt.InstantMethod;
            ev.MethodEvent += Method.StaticMethod;
            ev.Print("ppppppppppppppppp");
            Console.ReadKey();

这个时候,你再去用“=”就没有卵用了。
先看一下运行结果:

10.png

当触发事件的方法发生的时候,订阅该事件的方法都会按照订阅顺序进行执行动作。
其实,这已经算是一个很简版很简版的observe模式的例子了。
还有就是,有时候我们会遇到带有EventArgs参数的事件模型,这个是干什么用的呢?
其实这个是.Net Framework中的委托与事件,其有一个编码规范。
我们先看一下编码规范,下一篇再讲如何编写这样的委托与事件。
编码规则:

  • 委托类型的名称都应该以EventHandler结束。
  • 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型(就是监视对象),一个 EventArgs类型(或继承自EventArgs)(其存储了观察者感兴趣的数据,也就是事件触发的关键点)。
  • 事件的命名为 委托去掉 EventHandler之后剩余的部分。
  • 继承自EventArgs的类型应该以EventArgs结尾。

系列一就先记录到这里。

相关文章

  • C#——委托与事件系列一

    本来应该学习泛型与委托的,但是发现C#这里还没有系统的记录过委托与事件,所以先打算把委托与事件补上再继续泛型与委托...

  • C# 基础知识系列- 11 委托和事件

    0. 前言 事件和委托是C#中的高级特性,也是C#中很有意思的一部分。出现事件的地方,必然有委托出现;而委托则不一...

  • 教小明学一点点编程—C#篇(0)

    像小明这样使用C#的新同学,一定都会被C#的复杂的委托事件机制所困惑,那么我们不如解释一下什么是C#中委托。 委托...

  • C# 高级语言总结

    后续 1 C# 委托 委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 ...

  • [C#] 委托与事件(1)

    网上讲C#委托和事件的博文已经非常多了,其中也不乏一些深入浅出、条理清晰的文章。我之所以还是继续写,主要是借机整理...

  • [C#] 委托与事件(4)

    网上讲C#委托和事件的博文已经非常多了,其中也不乏一些深入浅出、条理清晰的文章。我之所以还是继续写,主要是借机整理...

  • [C#] 委托与事件(2)

    网上讲C#委托和事件的博文已经非常多了,其中也不乏一些深入浅出、条理清晰的文章。我之所以还是继续写,主要是借机整理...

  • [C#] 委托与事件(3)

    网上讲C#委托和事件的博文已经非常多了,其中也不乏一些深入浅出、条理清晰的文章。我之所以还是继续写,主要是借机整理...

  • (转).NET面试题系列[7] - 委托与事件

    委托和事件 委托在C#中具有无比重要的地位。 C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括...

  • unity & C#相关

    事件和委托 C#事件和Unity3d - CSDN博客 Unity常用的函数和遇到的C#的知识整理 Unity常用...

网友评论

      本文标题:C#——委托与事件系列一

      本文链接:https://www.haomeiwen.com/subject/ubcpottx.html