04-01 C# 委托的声明与实例化

25 篇文章 2 订阅

一、委托的定义

将方法当作参数传递,就是委托。

二、委托的声明

委托类似于方法,可以有参数和返回值,但是没有方法体(但是委托的本质不是一个方法),需要用delegate修饰,可以在类的内部声明,也可以在类的外部声明。

1、声明委托
namespace Lanyp.Course.Delegate
{
    #region delegate out of class 
    /// <summary>
    /// 定义在类的外部的无参数无返回值的委托
    /// </summary>
    public delegate void NoReturnNoParaOutClass();
    #endregion

    /// <summary>
    /// 自定义委托
    /// </summary>
    public class CoustomDelegate
    {
        #region delegate in class
        /// <summary>
        /// 无参数无返回值
        /// </summary>
        public delegate void NoReturnNoPara();
        /// <summary>
        /// 有参数无返回值
        /// </summary>
        public delegate void NoReturnHasPara(int x, int y);
        /// <summary>
        /// 无参数有返回值
        /// </summary>
        public delegate string HasReturnNoPara();
        /// <summary>
        /// 有参数有返回值
        /// </summary>
        public delegate int HasReturnHasPara(out int x, ref int y);
        #endregion
        
		
        }
}
2、在该类中定义方法,参数返回值与声明的委托对应
#region private methods
/// <summary>
/// 无参无返回值的函数
/// </summary>
private void NoReturnNoParaMethod()
{
    Console.WriteLine("无参数无返回值的方法");
}

/// <summary>
/// 有参数无返回值的函数
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
private void NoReturnHasParaMethod(int x, int y)
{
    Console.WriteLine($"{x}+{y}={x + y}");
}

/// <summary>
/// 无参数有返回值的函数
/// </summary>
private string HasReturnNoParaMethod()
{
    return "无参数有返回值的方法";
}

/// <summary>
/// 有参数有返回值的函数
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
private int HasReturnHasParaMethod(out int x, ref int y)
{
    x = 2;
    return x + y;
}
#endregion
3、委托的实例化与调用
  • 委托的实例化
    委托的实例化类似与类的实例化,如NoReturnNoPara noReturnNoPara = new NoReturnNoPara(NoReturnNoParaMethod);,但是区别在于需要将一个方法当作参数传递过去,需要注意的是,传过去的方法的参数与返回值必须与声明的委托一致。
  • 执行委托的两种方式:
    (1)调用Invoke函数:noReturnNoPara.Invoke();
    (2)直接调用实例化对象,如noReturnNoPara();
#region public methods
/// <summary>
/// 主方法
/// </summary>
public void Show()
{
    Console.WriteLine("=========================无参无返回值的委托====================");
    {
        //1、委托可以实例化,在实例化的过程中需要将一个方法当作参数传递过去
        NoReturnNoPara noReturnNoPara = new NoReturnNoPara(NoReturnNoParaMethod);
        //2、执行委托的两种方式
        //noReturnNoPara.Invoke(); //方式一
        noReturnNoPara();//方式二
        //noReturnNoPara.BeginInvoke(null,null); //分配一个线程去执行方法,多线程中使用
        //noReturnNoPara.EndInvoke(null);//多线程中使用
    }

    Console.WriteLine("=========================有参数无返回值的委托====================");
    {
        //3、实例化的时候要求传递进来的方法结构与委托一致:要求参数和返回值与委托保持一致
        //NoReturnHasPara noReturnHasPara = new NoReturnHasPara(NoReturnNoParaMethod); //错误示范
        NoReturnHasPara noReturnHasPara = new NoReturnHasPara(NoReturnHasParaMethod); //正确示范
        //noReturnHasPara.Invoke(1, 3);//方式一
        noReturnHasPara(1, 3);//方式二

    }

    Console.WriteLine("=========================无参数有返回值的委托====================");
    {
        HasReturnNoPara hasReturnNoPara = new HasReturnNoPara(HasReturnNoParaMethod);
        string result = hasReturnNoPara.Invoke();
        Console.WriteLine(result);
    }

    Console.WriteLine("=========================有参数有返回值的委托====================");
    {
        HasReturnHasPara hasReturnHasPara = new HasReturnHasPara(HasReturnHasParaMethod);
        int x = 0;
        int y = 3;
        int result = hasReturnHasPara.Invoke(out x, ref y);
        Console.WriteLine($"{x}+{y}={x + y}");
    }
    Console.ReadKey();
}
4、委托的本质

委托的本质是一个类,继承自MulticastDelegate特殊类
在这里插入图片描述

三、委托的应用场景

思考:有两个学生,分别是北京人和上海人,他们的方言不同,如何实现不同地区的同学向别人打招呼?

  • 方案一:利用枚举,优势在于没有冗余代码,但是缺点在于每次新增地名都需要修改枚举和方法,造成代码不稳定,耦合程度高
  • 方案二:每次新增一个地方就新增一个方法:相对于方案一优势在于不用修改太多的代码,耦合低,稳定性更高,缺点在于冗余代码太多
/// <summary>
/// 如果需要实现不同的地区的同学打招呼,有以下两种常规方案
/// </summary>
public class SayHi
{
    #region 方案一:利用枚举,优势在于没有冗余代码,但是缺点在于每次新增地名都需要修改枚举和方法,造成代码不稳定,耦合程度高
    public enum From
    {
        Shanghai,
        Beijing
    }

    /// <summary>
    /// 利用枚举约束,使调用者尽量少出错
    /// </summary>
    /// <param name="name"></param>
    /// <param name="from"></param>
    public void SayAction(string name, From from)
    {
        Console.WriteLine("招招手~~~~");
        switch (from)
        {
            case From.Shanghai:
                Console.WriteLine($"{name}:侬好!");
                break;
            case From.Beijing:
                Console.WriteLine($"{name}:你好!");
                break;
            default:
                throw new Exception("From type was wrong!");
        }
    }
    #endregion

    #region 方案二:每次新增一个地方就新增一个方法:相对于方案一优势在于不用修改太多的代码,耦合低,稳定性更高,缺点在于冗余代码太多
    public void ShangHai(string name)
    {
        Console.WriteLine("招招手~~~~");
        Console.WriteLine($"{name}:侬好!");
    }
    
    public void Beijing(string name)
    {
        Console.WriteLine("招招手~~~~");
        Console.WriteLine($"{name}:你好!");
    }
    #endregion
}

那么有没有更好的解决方案呢?

  • 终极解决方案:行为设计模式,利用委托传进来不同的方法,执行不同地区的学生的打招呼的方式
  • 这样做的优点:
    1、增加公共业务逻辑方便,只需要在公共方法内部增加即可,既减少代码的冗余,又最大程度保证程序的稳定
    2、增加一个新的业务逻辑模块(新增一个地区的人打招呼),逻辑由调用者(Student)提供,可以做到逻辑解耦
/// <summary>
/// 委托
/// </summary>
/// <param name="name"></param>
public delegate void SayHiDelegate(string name);

/// <summary>
/// 扩展方法
/// </summary>
public static class StudentExtension
{
	#region 调用者提供的业务逻辑
    public static void ShangHai(this Student student, string name)
    {
        Console.WriteLine($"{name}:侬好!");
    }

    public static void HongKong(this Student student, string name)
    {
        Console.WriteLine($"{name}:雷猴!");
    }

    public static void Beijing(this Student student, string name)
    {
        Console.WriteLine($"{name}:你好!");
    }
	#endregion
	
	#region 公共方法
    /// <summary>
    /// 终极解决方案:行为设计模式,利用委托传进来不同的方法,执行不同地区的学生的打招呼的方式
    /// 优势:
    ///   1、在该方法中可以增加公共业务逻辑,可以减少代码的冗余
    ///   2、增加一个新的业务逻辑模块(新增一个地区的人打招呼),逻辑由调用者提供,可以做到逻辑解耦
    /// </summary>
    /// <param name="student"></param>
    /// <param name="name"></param>
    /// <param name="sayHiDelegate"></param>
    public static void Action(this Student student, string name, SayHiDelegate sayHiDelegate)
    {
        Console.WriteLine("招招手~~~");
        sayHiDelegate.Invoke(name);
    }
    #enregion
}

调用时,只需要将各个不同地区的打招呼方式的扩展方法传递到委托中即可

{
    //上海人打招呼
    Console.WriteLine("======================上海人打招呼====================");
    Student student = new Student()
    {
        Name = "张三"
    };
    SayHiDelegate studentDelegate = new SayHiDelegate(student.ShangHai);
    student.Action(student.Name, studentDelegate);
}
{
    //北京人打招呼
    Console.WriteLine("======================北京人打招呼====================");
    var student = new Student()
    {
        Name = "王五"
    };
    var studentDelegate = new SayHiDelegate(student.Beijing);
    student.Action(student.Name, studentDelegate);
}

结论:

  • 如果在工作中的代码耦合严重,公共逻辑与业务逻辑之间本应该分开,可以使用委托来解耦
  • 如果代码冗余,可以使用委托来减少冗余代码。

四、代码地址

C#高级编程之委托

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值