C#中委托(delegate)详解

KenTuring 2024-10-14 12:35:01 阅读 82

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

无返回值无参数

<code>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实例进行加法和减法运算。通过这种方式,我们可以在计算完成后触发事件并通知订阅者,使代码更加灵活和可扩展。

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



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。