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
的委托类型,它可以引用任何无返回值且无参数的方法。然后,我们定义了两个方法LogInfo
和LogError
,分别用于记录信息日志和错误日志。
在Main
方法中,我们创建了一个LogDelegate
的实例,并将其初始化为null
。然后,我们使用+=
操作符将LogInfo
和LogError
方法添加到委托实例中。最后,我们调用委托实例,依次执行绑定的方法,并输出日志信息。
通过这种方式,我们可以使用多播委托来动态地绑定多个方法,并在调用委托时依次执行这些方法。这使得代码更加灵活和可扩展。
// 同样,也可以将LogError方法从委托实例移除
logDelegate += LogError;
//为了考虑安全,可以增加对委托是否为空的判断
logDelegate?.invoke();
Action与Func
在C#中,Action
和Func
是预定义的委托类型,用于简化委托的定义和使用。Action
用于表示无返回值的方法,而Func
用于表示有返回值的方法。
下面是一个使用Action
和Func
简化委托的例子,展示了如何定义和使用这些预定义委托类型。
假设我们有一个简单的计算器程序,可以进行加法和减法运算,并且可以记录日志信息。我们可以使用Action
和Func
来实现这些功能。
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);
}
}
在这个例子中,我们使用了Action
和Func
来定义和使用委托。
Action LogInfo
:定义了一个无返回值且无参数的委托,用于记录信息日志。Action<string> LogMessage
:定义了一个无返回值且有一个string
参数的委托,用于记录日志信息。Func<int, int, int> Add
:定义了一个接受两个int
参数并返回一个int
结果的委托,用于加法运算。Func<int, int, int> Subtract
:定义了一个接受两个int
参数并返回一个int
结果的委托,用于减法运算。
在Main
方法中,我们使用这些委托来记录日志信息和进行加法、减法运算。通过这种方式,我们可以使用Action
和Func
来简化委托的定义和使用,使代码更加简洁和易读。
匿名函数和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
实例进行加法和减法运算。通过这种方式,我们可以在计算完成后触发事件并通知订阅者,使代码更加灵活和可扩展。
注意:委托使用后记得使用-=
来清除,避免泄露。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。