微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

CSharp中委托与事件技术详解:一什么是委托

在C#语言中,委托无处不在,在C#框架(包括.NET)中,委托无处不在

1 委托

1.1 什么是委托

委托就是一个方法,我们先看一下如下代码

public delegate void noreturnnoparp();

public delegate void noreturnnoparpSum(int sum);

private void btnCreateDelegate_Click(object sender, EventArgs e)
{
    //noreturnnoparp noreturnnoparp = new noreturnnoparp(SayHello);
    noreturnnoparp noreturnnoparp = SayHello;
    //noreturnnoparp.Invoke();
    noreturnnoparp();

    noreturnnoparpSum noreturnnoparpSum = SayHello;
    noreturnnoparpSum.Invoke(3);
}

public void SayHello()
{
    Console.WriteLine("Hello World");
}

public void SayHello(int Sum)
{
    for (int i = 0; i < Sum; i++)
    {
        Console.WriteLine($"第{i}次,Hello World");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPjDlhSz-1613956810883)(1.1声明委托.jpg)]

我们使用反编译工具查看一下代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JQQZhlbZ-1613956810885)(1.1反编译查看IL语言.jpg)]

.class   类
.ctor   构造函数
.method 方法

我们可以得到以下结论:

  • 委托在IL中就是一个
  • 继承自System.MulticastDelegate(特殊类,该类无法继承)
  • 能够做到方法当作参数在另一个方法中传递或调用
  • 从上面可以看出,调用方法和委托的返回类型,参数类型都必须一致。
  • 在Invoke时调用方法的运行且在Invoke时传入所需要参数
  • BeginInvoke和EndInvoke是启用一个多线程使用,如果有需要可以借鉴博主《万字长文主讲介绍CSharp多线程、多进程并行开发》https://qlygmwcx.blog.csdn.net/article/details/112499286

1.2 为什么会存在委托,为什么要用委托

委托的类的实例可以放入一个方法,实例在Invoke时,就调用方法,说起来是在执行方法,为啥要做成三个步骤,基于此我们来做一个小案例分析一下。

现在有一个人,每一次见到别人都需要打招呼,见到中国人要说:{早上好},见到美国人要说:{Good Morning}。

1.2.1 基础代码

private void btnBaseCode_Click(object sender, EventArgs e)
{
    Person pPerson = new Person("蔡名洋");
    pPerson.CallGreeting("xiaocai");
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    public class Person
    {
        public Person(string strPersonName)
        {
            PersonName = strPersonName;
        }

        public string PersonName
        {
            get;
            private set;
        }

        public void CallGreeting(string strCallPersonName)
        {
            Console.WriteLine("招手示意..................");

            Console.WriteLine($"早上好:{strCallPersonName}");

            Console.WriteLine("挥手告别..................");
        }
    }
}

1.2.2 通过不同的函数实现对不同人群的打招呼

public class Person
{
    public Person(string strPersonName)
    {
        PersonName = strPersonName;
    }

    public string PersonName
    {
        get;
        private set;
    }

    public void CallGreeting4Chinese(string strCallPersonName)
    {
        Console.WriteLine("招手示意..................");
        Console.WriteLine($"早上好:{strCallPersonName}");
        Console.WriteLine("挥手告别..................");
    }

    public void CallGreeting4American(string strCallPersonName)
    {
        Console.WriteLine("招手示意..................");
        Console.WriteLine($"Good Morning :{strCallPersonName}");
        Console.WriteLine("挥手告别..................");
    }
}

1.2.3 通过不同枚举实现对不同人群的打招呼


private void btnBaseCodeOverload_Click(object sender, EventArgs e)
{
    Person pPerson = new Person("蔡名洋");
    pPerson.CallGreeting("小菜", PersonType.ChinesePerson);
    pPerson.CallGreeting("xiaocai", PersonType.ChinesePerson);
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    public class Person
    {
        public Person(string strPersonName)
        {
            PersonName = strPersonName;
        }

        public string PersonName
        {
            get;
            private set;
        }

        public void CallGreeting(string strCallPersonName,PersonType personType)
        {
            Console.WriteLine("招手示意..................");

            switch (personType)
            {
                case PersonType.ChinesePerson:
                    Console.WriteLine($"早上好:{strCallPersonName}");
                    break;
                case PersonType.AmericanPerson:
                    Console.WriteLine($"Good Morning :{strCallPersonName}");
                    break;
            }

            Console.WriteLine("挥手告别..................");
        }
    }

    public enum PersonType
    { 
        /// <summary>
        /// 中国人
        /// </summary>
        ChinesePerson=0,

        /// <summary>
        /// 美洲人
        /// </summary>
        AmericanPerson=1,
    }
}

点评1.2.2和1.2.3部分的代码,以及思考

  • 1.2.2中的代码采用扩展函数的方式扩展存在以下几个问题:

    • 如果需要统一修改打招呼前与打招呼后的动作(游戏中称呼为:前摇和后摆) 是否需要在所有函数中进行修改
    • 如果需要扩展过度,从类的代码整体分布上来看,Person的职责过的,反而弱化了Person类的操作。
  • 1.2.3中的代码采用枚举的方式进行扩展存在以下问题:

    • 每一次扩展都需要扩展switch case从一定意义上违反了开闭原则:每一次的修改都需要修改枚举和switch case中的代码
  • 如果我们上述中来看,其实我们可以认定打招呼也是一个对象,每一种对象对每一种人都有一种独特的打招呼方式

1.2.4 封装打招呼类

1.2.4.1 无工厂类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    public interface ICallGreeting
    {
        void CallGreeting(string strCallPersonName);
    }
}


public class AmericanCallGreeting : ICallGreeting
{
    public void CallGreeting(string strCallPersonName)
    {
        Console.WriteLine($"早上好:{strCallPersonName}");
    }
}

public class ChineseCallGreeting : ICallGreeting
{
    public void CallGreeting(string strCallPersonName)
    {
        Console.WriteLine($"早上好:{strCallPersonName}");
    }
}


//界面UI代码
private void btnBaseCodeInterface_Click(object sender, EventArgs e)
{
    Person pPerson = new Person("蔡名洋");

    ICallGreeting pChineseCallGreeting = new ChineseCallGreeting();
    pPerson.CallGreeting4Interface("小菜", pChineseCallGreeting);
    ICallGreeting pAmericanCallGreeting = new AmericanCallGreeting();
    pPerson.CallGreeting4Interface("xiaocai", pAmericanCallGreeting);
}

1.2.4.2 工厂类加装

//界面UI代码
private void btnBaseCodeInterface_Click(object sender, EventArgs e)
{
    Person pPerson = new Person("蔡名洋");

    //ICallGreeting pChineseCallGreeting = new ChineseCallGreeting();
    //pPerson.CallGreeting4Interface("小菜", pChineseCallGreeting);
    //ICallGreeting pAmericanCallGreeting = new AmericanCallGreeting();
    //pPerson.CallGreeting4Interface("xiaocai", pAmericanCallGreeting);

    ICallGreeting pChineseCallGreeting =CallGreetingFactory.GetCallGreeting(PersonType.ChinesePerson);
    pPerson.CallGreeting4Interface("小菜", pChineseCallGreeting);
    ICallGreeting pAmericanCallGreeting = CallGreetingFactory.GetCallGreeting(PersonType.AmericanPerson);
    pPerson.CallGreeting4Interface("xiaocai", pAmericanCallGreeting);
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    public static class CallGreetingFactory
    {
        public static ICallGreeting GetCallGreeting(PersonType pPersonType)
        {
            switch (pPersonType)
            {
                case PersonType.ChinesePerson:
                    return new ChineseCallGreeting();
                case PersonType.AmericanPerson:
                    return new AmericanCallGreeting();
            }
            return null;
        }
    }
}

1.2.5 由上述铺垫引出Delegate类和delegate关键字

delegate:https://msdn.microsoft.com/zh-cn/library/ms173171.aspx

Delegate:https://msdn.microsoft.com/zh-cn/library/system.delegate(v=vs.110).aspx

  • 简单的来说就是:Delegate是个类,基类,抽象类。delegate是一个关键字

更深入一点则可以这样理解:

  1. Delegate 类是委托类型的基类。 然而,只有系统和编译器可以显式地从 Delegate 类或 MulticastDelegate 类派生。 此外,还不允许从委托类型派生新类型。 Delegate 类不是委托类型,该类用于派生委托类型。

  2. 大多数语言实现 delegate 关键字,这些语言的编译器能够从 MulticastDelegate 类进行派生;所以,用户应当使用语言所提供的 delegate 关键字。

private void btnBaseCodeDeleggate_Click(object sender, EventArgs e)
{
    Person pPerson = new Person("蔡名洋");

    CallGreetingDelegate pChineseCallGreetingDelegate=DelegateCallGreetingFactory.GetCallGreetingDelegate(PersonType.ChinesePerson);
    pPerson.CallGreeting4Delegate("小菜", pChineseCallGreetingDelegate);

    CallGreetingDelegate AmericanCallGreetingDelegate = DelegateCallGreetingFactory.GetCallGreetingDelegate(PersonType.AmericanPerson);
    pPerson.CallGreeting4Delegate("xiaocai", AmericanCallGreetingDelegate);
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelegateDemo
{
    public delegate void CallGreetingDelegate(string strCallPersonName);

    public static class DelegateCallGreetingFactory
    {
        public static CallGreetingDelegate GetCallGreetingDelegate(PersonType pPersonType)
        {
            CallGreetingDelegate pReturnCallGreetingDelegate = null;
            switch (pPersonType)
            {
                case PersonType.ChinesePerson:
                    pReturnCallGreetingDelegate = CallGreeting4Chinese;
                    break;
                case PersonType.AmericanPerson:
                    pReturnCallGreetingDelegate = CallGreeting4American;
                    break;
            }
            return pReturnCallGreetingDelegate;
        }



        public static void CallGreeting4Chinese(string strCallPersonName)
        {
            Console.WriteLine($"早上好:{strCallPersonName}");
        }

        public static void CallGreeting4American(string strCallPersonName)
        {
            Console.WriteLine($"Good Morning :{strCallPersonName}");
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐