C#中委托(delegate)详解

简单理解:方法的指针或容器(浅->深),那么当它与方法关联时也应具备这个方法的特性。

无返回值无参数

public class Example1{
    private delegate void MyDelegate();//声明时像方法一样,没有方法体,有关键字
    
    private delegate _myDelegate;
    
    public void Main(){
        _myDelegate = PrintSum;//使用方法给声明的委托赋值
        _myDelegate();//执行
    }
    //定义方法
    private void PrintSum(){
        var sum = 0;
        for(var i=1;i<=100;i++){
            sum += i;
        }
        Console.WriteLine(sum);
    }
}

有返回有参数

public class Example2{
    private delegate int MyDelegate(int a,int b);//声明时像方法一样,没有方法体,有关键字
    
    private delegate _myDelegate;
    
    public void Main(){
        _myDelegate = Add;//使用方法给声明的委托赋值
        var result = =_myDelegate(3,5);//执行
        Console.WriteLine(result);
    }
    //定义方法
    private void Add(int a,int b){
        return a + b;
    }
}

为什么需要委托

假设一个需求,一个角色进入游戏需要不同的full,buff包含使用特效的方法、消耗技能点的方法、增加属性值的方法。

public class Example3
{

    public void Main()
    {
        Castskill();
        Castskill1();
        Castskill2();
    }
    private void Castskill()
    {
        ConsumeMP();//消耗MP
        PlayEffects();//播放特效
        DoDamage();
    }
    private void Castskill1()
    {
        ConsumeMP();//消耗MP
        PlayEffects();//播放特效
        DoHeal();
    }
    private void Castskill2()
    {
        ConsumeMP();//消耗MP
        PlayEffects();//播放特效
        DoTeleport();
    }
}

这里,是否觉得过于臃肿,不利于维护呢?

增加delegate改进,使用委托替代重复的方法。

public class Example3
{
    private delegate void SkillDelegate();

    public void Main()
    {
        Castskill();
        Castskill1();
        Castskill2();
    }
    private void Castskill(SkillDelegate skillDelegate)
    {
        ConsumeMP();//消耗MP
        PlayEffects();//播放特效
        skillDelegate();
    }
    
}

Multicast Delegate

在C#中,委托可以存放多个方法,这种委托称为多播委托(Multicast Delegate)。多播委托允许你将多个方法绑定到一个委托实例上,并在调用委托时依次执行这些方法。

下面是一个使用多播委托的例子,展示了如何将多个方法绑定到一个委托实例上,并在调用委托时依次执行这些方法。

假设我们有一个简单的日志系统,可以记录不同类型的日志信息(例如,信息日志和错误日志)。我们可以使用多播委托来实现这个功能。

using System;

// 定义一个委托类型,表示无返回值且无参数的方法
public delegate void LogDelegate();

class Program
{
    // 定义记录信息日志的方法
    public static void LogInfo()
    {
        Console.WriteLine("记录信息日志");
    }

    // 定义记录错误日志的方法
    public static void LogError()
    {
        Console.WriteLine("记录错误日志");
    }

    static void Main(string[] args)
    {
        // 创建一个多播委托实例
        LogDelegate logDelegate = null;

        // 将LogInfo方法添加到委托实例中
        logDelegate += LogInfo;

        // 将LogError方法添加到委托实例中
        logDelegate += LogError;

        // 调用委托实例,依次执行绑定的方法
        logDelegate();
    }
}

在这个例子中,我们定义了一个名为LogDelegate的委托类型,它可以引用任何无返回值且无参数的方法。然后,我们定义了两个方法LogInfoLogError,分别用于记录信息日志和错误日志。

Main方法中,我们创建了一个LogDelegate的实例,并将其初始化为null。然后,我们使用+=操作符将LogInfoLogError方法添加到委托实例中。最后,我们调用委托实例,依次执行绑定的方法,并输出日志信息。

通过这种方式,我们可以使用多播委托来动态地绑定多个方法,并在调用委托时依次执行这些方法。这使得代码更加灵活和可扩展。

// 同样,也可以将LogError方法从委托实例移除
        logDelegate += LogError;
//为了考虑安全,可以增加对委托是否为空的判断
		logDelegate?.invoke();

Action与Func

在C#中,ActionFunc是预定义的委托类型,用于简化委托的定义和使用。Action用于表示无返回值的方法,而Func用于表示有返回值的方法。

下面是一个使用ActionFunc简化委托的例子,展示了如何定义和使用这些预定义委托类型。

假设我们有一个简单的计算器程序,可以进行加法和减法运算,并且可以记录日志信息。我们可以使用ActionFunc来实现这些功能。

using System;

class Program
{
    // 定义一个Action委托,表示无返回值且无参数的方法
    public static Action LogInfo = () => Console.WriteLine("记录信息日志");

    // 定义一个Action委托,表示无返回值且有一个string参数的方法
    public static Action<string> LogMessage = (message) => Console.WriteLine("记录日志: " + message);

    // 定义一个Func委托,表示接受两个int参数并返回一个int结果的方法
    public static Func<int, int, int> Add = (a, b) => a + b;
    public static Func<int, int, int> Subtract = (a, b) => a - b;

    static void Main(string[] args)
    {
        // 使用Action委托记录信息日志
        LogInfo();

        // 使用Func委托进行加法运算
        int result = Add(5, 3);
        LogMessage("5 + 3 = " + result);

        // 使用Func委托进行减法运算
        result = Subtract(5, 3);
        LogMessage("5 - 3 = " + result);
    }
}

在这个例子中,我们使用了ActionFunc来定义和使用委托。

  • Action LogInfo:定义了一个无返回值且无参数的委托,用于记录信息日志。
  • Action<string> LogMessage:定义了一个无返回值且有一个string参数的委托,用于记录日志信息。
  • Func<int, int, int> Add:定义了一个接受两个int参数并返回一个int结果的委托,用于加法运算。
  • Func<int, int, int> Subtract:定义了一个接受两个int参数并返回一个int结果的委托,用于减法运算。

Main方法中,我们使用这些委托来记录日志信息和进行加法、减法运算。通过这种方式,我们可以使用ActionFunc来简化委托的定义和使用,使代码更加简洁和易读。

匿名函数和lamda表达式

使用匿名方法和Lambda表达式可以进一步简化上面的例子。下面是一个使用匿名方法和Lambda表达式简化委托的例子:

using System;

class Program
{
    // 使用Lambda表达式定义Action委托,表示无返回值且无参数的方法
    public static Action LogInfo = () => Console.WriteLine("记录信息日志");

    // 使用Lambda表达式定义Action委托,表示无返回值且有一个string参数的方法
    public static Action<string> LogMessage = (message) => Console.WriteLine("记录日志: " + message);

    // 使用Lambda表达式定义Func委托,表示接受两个int参数并返回一个int结果的方法
    public static Func<int, int, int> Add = (a, b) => a + b;
    public static Func<int, int, int> Subtract = (a, b) => a - b;

    static void Main(string[] args)
    {
        // 使用Action委托记录信息日志
        LogInfo();

        // 使用Func委托进行加法运算
        int result = Add(5, 3);
        LogMessage("5 + 3 = " + result);

        // 使用Func委托进行减法运算
        result = Subtract(5, 3);
        LogMessage("5 - 3 = " + result);
    }
}

在这个例子中,我们使用了Lambda表达式来定义和使用委托。

  • Action LogInfo:使用Lambda表达式定义了一个无返回值且无参数的委托,用于记录信息日志。
  • Action<string> LogMessage:使用Lambda表达式定义了一个无返回值且有一个string参数的委托,用于记录日志信息。
  • Func<int, int, int> Add:使用Lambda表达式定义了一个接受两个int参数并返回一个int结果的委托,用于加法运算。
  • Func<int, int, int> Subtract:使用Lambda表达式定义了一个接受两个int参数并返回一个int结果的委托,用于减法运算。

Main方法中,我们使用这些委托来记录日志信息和进行加法、减法运算。通过这种方式,我们可以使用Lambda表达式来简化委托的定义和使用,使代码更加简洁和易读。

回调CallBack

在C#中,回调方法(callback)是一种常见的编程模式,用于在某个操作完成后执行特定的逻辑。我们可以通过委托来实现回调方法。下面是一个使用回调方法的例子,展示了如何在计算完成后执行回调逻辑。

假设我们有一个简单的计算器程序,可以进行加法和减法运算,并且在运算完成后执行回调方法记录日志信息。我们可以使用委托来实现这个功能。

using System;

class Program
{
    // 定义一个Action委托,表示无返回值且有一个string参数的方法
    public static Action<string> LogMessage = (message) => Console.WriteLine("记录日志: " + message);

    // 定义一个Func委托,表示接受两个int参数并返回一个int结果的方法
    public static Func<int, int, int> Add = (a, b) => a + b;
    public static Func<int, int, int> Subtract = (a, b) => a - b;

    // 定义一个方法,接受两个int参数、一个Func委托和一个Action委托,用于执行计算并调用回调方法
    public static void PerformCalculation(int x, int y, Func<int, int, int> calculation, Action<string> callback)
    {
        int result = calculation(x, y);
        callback($"计算结果: {result}");
    }

    static void Main(string[] args)
    {
        // 使用PerformCalculation方法进行加法运算,并使用LogMessage作为回调方法
        PerformCalculation(5, 3, Add, LogMessage);

        // 使用PerformCalculation方法进行减法运算,并使用LogMessage作为回调方法
        PerformCalculation(5, 3, Subtract, LogMessage);
    }
}

在这个例子中,我们定义了一个PerformCalculation方法,该方法接受两个int参数、一个Func<int, int, int>委托和一个Action<string>委托。Func<int, int, int>委托用于执行计算,Action<string>委托用于在计算完成后执行回调逻辑。

Main方法中,我们使用PerformCalculation方法进行加法和减法运算,并使用LogMessage作为回调方法记录日志信息。通过这种方式,我们可以在计算完成后执行特定的回调逻辑,使代码更加灵活和可扩展。

事件

在C#中,事件(Event)是一种特殊的委托,用于实现发布-订阅模式。事件允许一个类或对象向其他类或对象通知发生了某些事情。下面是一个使用事件的例子,展示了如何在计算完成后触发事件并通知订阅者。

假设我们有一个简单的计算器程序,可以进行加法和减法运算,并且在运算完成后触发事件通知订阅者。我们可以使用事件来实现这个功能。

using System;

// 定义一个事件参数类,继承自EventArgs
public class CalculationEventArgs : EventArgs
{
    public int Result { get; }
    public CalculationEventArgs(int result)
    {
        Result = result;
    }
}

class Calculator
{
    // 定义一个事件,使用EventHandler<CalculationEventArgs>作为委托类型
    public event EventHandler<CalculationEventArgs> CalculationPerformed;

    // 定义一个方法,接受两个int参数和一个Func委托,用于执行计算并触发事件
    public void PerformCalculation(int x, int y, Func<int, int, int> calculation)
    {
        int result = calculation(x, y);
        OnCalculationPerformed(new CalculationEventArgs(result));
    }

    // 触发事件的方法,使用protected virtual修饰,便于子类重写
    protected virtual void OnCalculationPerformed(CalculationEventArgs e)
    {
        CalculationPerformed?.Invoke(this, e);
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 创建Calculator实例
        Calculator calculator = new Calculator();

        // 订阅CalculationPerformed事件
        calculator.CalculationPerformed += (sender, e) =>
        {
            Console.WriteLine($"计算结果: {e.Result}");
        };

        // 定义加法和减法运算
        Func<int, int, int> Add = (a, b) => a + b;
        Func<int, int, int> Subtract = (a, b) => a - b;

        // 使用Calculator实例进行加法运算
        calculator.PerformCalculation(5, 3, Add);

        // 使用Calculator实例进行减法运算
        calculator.PerformCalculation(5, 3, Subtract);
    }
}

在这个例子中,我们定义了一个CalculationEventArgs类,继承自EventArgs,用于传递计算结果。然后,我们在Calculator类中定义了一个CalculationPerformed事件,使用EventHandler<CalculationEventArgs>作为委托类型。

Calculator类中,我们定义了一个PerformCalculation方法,该方法接受两个int参数和一个Func<int, int, int>委托,用于执行计算并触发事件。我们还定义了一个OnCalculationPerformed方法,用于触发事件,并使用protected virtual修饰,便于子类重写。

Main方法中,我们创建了一个Calculator实例,并订阅了CalculationPerformed事件。然后,我们定义了加法和减法运算,并使用Calculator实例进行加法和减法运算。通过这种方式,我们可以在计算完成后触发事件并通知订阅者,使代码更加灵活和可扩展。

注意:委托使用后记得使用-=来清除,避免泄露。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值