zoukankan      html  css  js  c++  java
  • C# 委托

    一、前言:每次看到委托和事件,心理面总是不自在,原因大家都懂,但是委托和事件在.NET FrameWork里面的应用非常的广泛,所以熟练的掌握委托和事件对一个.NET开发人员来说是十分重要的,所以花半天的时间来彻底的扫下盲点,争取能carry掉!

    二、概述

    1、作用:委托的作用是将方法作为参数传递给方法

    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)
            {   
                Program p=new Program();
                p.SayHello("张三");
            }
            public void SayHello(string name)
            {
                ChineseSayHello(name);
            }
    
            private void ChineseSayHello(string name)
            {
                Console.WriteLine("你好:{0}",name);
            }
        }
    }

    上面的代码主要是一个打招呼程序,当你给SayHello()方法输入参数姓名是,该程序就会吊用中文式的SayHello的方法,但是有一个问题,现在这个程序需要国际化,需要填加其他国家的SayHello()方法,如何美国的,那么这个时候应该加一个language参数,来区分不同的国家,下面是改进后的代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Delegate
    {
        class SayHello1
        {
            static void Main(string[] args) {
                SayHello1 s1 = new SayHello1();
                s1.SayHello("张三", Country.Chinese);
                s1.SayHello("张三", Country.America);
            }
            public void SayHello(string _name, Country _country)
            {
                switch (_country) {
                    case Country.America: EnglishSayHello(_name); break;
                    case Country.Chinese: ChineseSayHello(_name); break;
                    default: ChineseSayHello(_name); break;
                }
            }
            private void EnglishSayHello(string _name) {
                Console.WriteLine("Hello {0}", _name);
            }
            private void ChineseSayHello(string _name)
            {
                Console.WriteLine("你好 {0}", _name);
            }
        }
        public enum Country { 
    
            //中国
            Chinese,
            //美国
            America
        }
    }

    上面的代码通过枚举和switch判断,解决了国际化的问题,但是这样的代码耦合度太高,试想一下,当我们每加一个国家,SayHello()方法就要改变,这是不妥的,话句话说,就是假设我们加一个韩国的SayHello()的方法,在设计层面上来看它仅仅是加了一个韩国的SayHello的方法,但是从代码和角度看,他改变的是整个SayHello()方法的结构,这是不妥的,中国和美国的SayHello方法不应该因为额外加了一个韩国的SayHello方法所出现的安全问题买单。所以这种方法虽然解决了问题,但是产生了不必要的问题,代码的扩展性很差。

    下面通过委托来解决上面的问题

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Delegate
    {
        //定义一个委托EventHander是微软定义委托的一种标准委托的名字+EventHander
        //定义了一个无返回值,参数为name的委托
        //注意委托定义的位置和string,delegate,SayHello2的位置是一样的,说明委托也应该是个类型,或者说类
        //但是委托的声明方式,却和类不一样。实际上委托最后确实会被编译成一个类.应为delegate是个类,所以任何可以声明类的地方都可以声明委托
    
        public delegate void SayHelloEventHander(string name);
        class SayHello2
        {
            private static void Main(string[] args) {
                SayHello2 s2 = new SayHello2();
                s2.SayHello("张三", s2.ChineseSayHello);
                s2.SayHello("zhangsan", s2.EnglishSayHello);
            }
            public void SayHello(string _name, SayHelloEventHander _sayHello) {
                _sayHello(_name);     
            }
            private void EnglishSayHello(string _name) {
                Console.WriteLine("hello:{0}", _name);
            }
            private void ChineseSayHello(string _name)
            {
                Console.WriteLine("你好:{0}", _name);
            }
        }
    }

    总结:

    <1>委托是一个类,任何可以声明类的地方,都可以声明委托.

    <2>委托可以定义方法的类型和返回值

    <3>通过使用委托,将方法作为参数传递给方法的方式,减少了程序中if else和switch语句出现的次数,增加了程序的可扩展性

    2、委托也是一种数据类型

    (1)、上面的代码中提到了,可以定义类的地方,就可以定义委托,那么我们就可以推断出,委托实际上也是一种数据类型,我们也可以像申明类一样的方式来申明委托.并调用它;

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Delegate
    {
        public class SayHello3
        {
            public delegate void SayHelloEventHandler(string _name);
            static void Main(string[] args)
            {
                SayHello3 s3 = new SayHello3();
                SayHelloEventHandler s1, s2;//定义了两个委托实例
                //为实例赋值
                s1 = s3.ChineseSayHello;
                s2 = s3.EnglishSayHello;
                s3.SayHello("张三", s1);
                s3.SayHello("张三", s2);
            }
            public void SayHello(string _name, SayHelloEventHandler sayHello)
            {
                sayHello(_name);
            }
            private void ChineseSayHello(string _name)
            {
                Console.WriteLine("你好:{0}", _name);
            }
            private void EnglishSayHello(string _name)
            {
                Console.WriteLine("hello:{0}", _name);
            }
        }
    }

    (2)、将多个方法绑定给同一个委托

    这是委托的一个特性:可以将多个方法赋给同一个委托,或者将多个方法绑定给同一个委托,当调用这个委托的时候,讲一次吊用该委托所绑定的方法;代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Delegate
    {
        class SayHello5
        {
            public delegate void SayHelloEventHandler(string _name);
            static void Main(string[] args) {
                SayHelloEventHandler sr1;
                SayHello5 s5 = new SayHello5();
                //如果需要给SayHelloEventHandler绑定多个方法,必须先给sr1赋初值,在做+=操作,否则编译器会报错
                sr1 = s5.EnglishSayHello;
                sr1 += s5.ChineseSayHello;
                sr1 -= s5.EnglishSayHello;
                sr1 += s5.EnglishSayHello;
                s5.SayHello("张三", sr1);
            }
            public void SayHello(string _name,SayHelloEventHandler sayHello) {
                sayHello(_name);
            }
            private void ChineseSayHello(string _name)
            {
                Console.WriteLine("你好:{0}", _name);
            }
    
            private void EnglishSayHello(string _name)
            {
                Console.WriteLine("hello:{0}", _name);
            }
        }
    }

    (3)上面代码中提到了当我们需要给一个委托绑定多个方法是,必须先给第一个赋初值在做+=运算,如果直接+=编译器则会报错。所以这个问题引申出第二种委托定义的方式,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Delegate
    {
        class Thread4
        {
            public delegate void SayHelloEventHandler(string _name);
            static void Main(string[] args)
            {
                //前面说过委托也是一种类型,他可以向类一样的创建实例
                SayHelloEventHander sh = new SayHelloEventHander(ChineseSayHello);//创建了一个SayHelloEventHandler的实例,并给SayHelloEventHandler构造函数赋了初值ChineseSayHello
                //然后就可以做+=操作,做后续绑定工作
                sh += EnglishHello;
            }
    
            private static void ChineseSayHello(string name)
            {
                
            }
            private static void EnglishHello(string name)
            {
    
            }
    
        }
    }

    (4)利用面向对象的方法,封装代码,给上面的代码解耦

    分析上面的代码:发现SayHello()这个方法是不变的,那我们就把它封装起来,我们把SayHello的方法封装成SayHelloManager类,外部程序直接通过SayHelloManager类来访问并设置对应的SayHello()方法和参数。

    using System;
    namespace Delegate
    {
        //定义一个无返回值,但是有一个name参数的委托
        public delegate void SayHelloEventHandler(string _name);
        class SayHello6
        {
            static void Main(string[] args)
            {   
                //第一种方法
                SayHelloManger sm = new SayHelloManger();
                sm.SayHelloEventHandler = ChineseSayHello;
                sm.SayHelloEventHandler += EnglishSayHello;
                sm.SayHello("张三", sm.SayHelloEventHandler);
    
    
                //第二种调用方式
                SayHelloManger sm1 = new SayHelloManger("张三", ChineseSayHello);
                sm1.SayHello();
                SayHelloManger sm2 = new SayHelloManger("张三",EnglishSayHello);
                sm2.SayHello();
            }
            static void ChineseSayHello(string _name){
                Console.WriteLine("你好:{0}", _name);
              }
            static void EnglishSayHello(string _name){
                Console.WriteLine("Hello:{0}", _name);
              }
        }
        //定义一个SayHelloManager类,将所有SayHello()方法需要的参数设置成实例,并给外部调用
        public class SayHelloManger
        {
            public string _name;
            public SayHelloEventHandler _sayHelloEventHandler;
            public SayHelloEventHandler SayHelloEventHandler
            {
                get { return _sayHelloEventHandler; }
                set { _sayHelloEventHandler = value; }
            }
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
            public SayHelloManger()
            {
            }
            public SayHelloManger(string _name, SayHelloEventHandler handler)
            {
                this.SayHelloEventHandler = handler;
                this.Name = _name;
            }
            public void SayHello()
            {
                this.SayHelloEventHandler(Name);
            }
            public void SayHello(string _name,SayHelloEventHandler SayHello)
            {
                SayHello(_name);
            }
        }
    }

  • 相关阅读:
    matlab中用来批量读取的dir函数
    cat 函数应用
    线性移不变系统
    为什么低频信息描述了图像在光滑部位的整体灰度信息,而高频部分则反映了图像在边缘、噪声等细节方面的表现?
    红灯检测宇视科技专利分析与总结2
    红灯检测宇视科技专利分析与总结1
    matlab中冒号的用法
    第一篇博文,大橙子的博客生涯要开始啦
    Spring Boot和Shiro整合
    Spring Boot + Redis使用短信平台发送验证码(腾讯云短信平台)
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/6347404.html
Copyright © 2011-2022 走看看