委托(Delegate)
委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自System.Delegate类
类似于将一件事情委托出去,然后等到何时的时机帮我去执行。而且运用委托还可以减少耦合。这些后面用例子说明。
先看一段简单的委托使用实例:
委托的简单实例
你肯定要先自己手动实现一下,熟悉一些方法
using System;
delegate void NumberChange(int n);
namespace Delegate
{
internal class Program
{
public delegate void DelegateExample(int n);
public static void Fun1(int a)
{
// do something
Console.WriteLine("Fun1 {0}",a);
}
public static void Fun2(int a)
{
// do something
Console.WriteLine("Fun2 {0}", a);
}
// 作为函数参数
public static void Fun3(int a,DelegateExample myDelegate)
{
myDelegate(a);
}
public static void Main(string[] args)
{
// 创建委托的几种方法
Console.WriteLine("-----------------------");
DelegateExample example_01 = new DelegateExample(Fun1);
example_01(10);
// 可以简化为
Console.WriteLine("-----------------------");
DelegateExample example_02 = Fun1;
example_02(10);
// 还可以覆盖
Console.WriteLine("-----------------------");
example_02 = Fun2;
example_02(30);
// 还可以添加
Console.WriteLine("-----------------------");
example_02 += Fun1;
example_02(30);
// 还可以删除
Console.WriteLine("-----------------------");
example_02 -= Fun1;
example_02(30);
// 还可以做为函数参数
Console.WriteLine("-----------------------");
Fun3(60,Fun1);
}
}
}
从这一段代码中肯定是看不出有什么作用的,还会怀疑这个委托有个啥用,直接调用函数不香么?
那么我们接着就是要看看为什么要用委托。
常规方法
常规方法的实现,我们要去显示一些数据
using System;
namespace Delegate
{
/// <summary>
/// 玩家数据
/// </summary>
public class PlayerStats
{
public string name;
public int kills;
public int deaths;
public int flagsCaptured;
}
/// <summary>
/// 显示玩家数据
/// </summary>
public class DisplayPlayerNames
{
int GetPlayStatsKills(PlayerStats playerStats)
{
return playerStats.kills;
}
int GetPlayStatsFlagsCaptured(PlayerStats playerStats)
{
return playerStats.flagsCaptured;
}
/// <summary>
/// 显示最强杀手
/// </summary>
/// <param name="playerstats">所有玩家状态</param>
/// <returns></returns>
public static string GetPlayNameMostKills(PlayerStats[] playerstats)
{
int bestScore = 0;
string name = "";
foreach (PlayerStats stats in playerstats)
{
int score = stats.kills;
if (score > bestScore)
{
bestScore = score;
name = stats.name;
}
}
return name;
}
/// <summary>
/// 显示被捕次数最多的玩家
/// </summary>
/// <param name="playerstats">所有玩家状态</param>
/// <returns></returns>
public static string GetPlayNameMostFlagsCaptured(PlayerStats[] playerstats)
{
int bestScore = 0;
string name = "";
foreach (PlayerStats stats in playerstats)
{
int score = stats.flagsCaptured;
if (score > bestScore)
{
bestScore = score;
name = stats.name;
}
}
return name;
}
}
public class PlayStats
{
public static void Run()
{
PlayerStats[] playerStats = new PlayerStats[4];
for (int i = 0; i < playerStats.Length; i++)
{
playerStats[i]= new PlayerStats();
playerStats[i].deaths = i;
playerStats[i].kills = i;
playerStats[i].flagsCaptured = playerStats.Length - i;
playerStats[i].name = (i+1).ToString();
}
string mostKills = DisplayPlayerNames.GetPlayNameMostKills(playerStats);
Console.WriteLine("最强杀手:{0}",mostKills);
string mostFlagsCaptured = DisplayPlayerNames.GetPlayNameMostFlagsCaptured(playerStats);
Console.WriteLine("被捕次数最多的是:{0}",mostFlagsCaptured);
}
}
}
从上面的代码可以看到,在DisplayPlayNams中的两个函数代码几乎相同唯一不同的是,只有在获取score有些不同。现在我们加入委托优化。
委托的运用
using System;
namespace DelegatePro
{
/// <summary>
/// 玩家数据
/// </summary>
public class PlayerStats
{
public string name;
public int kills;
public int deaths;
public int flagsCaptured;
}
/// <summary>
/// 显示玩家数据
/// </summary>
public class DisplayPlayerNames
{
// 最高分数委托
public delegate int TopScoreDelegate(PlayerStats playerStats);
public static int GetPlayStatsKills(PlayerStats playerStats)
{
return playerStats.kills;
}
public static int GetPlayStatsFlagsCaptured(PlayerStats playerStats)
{
return playerStats.flagsCaptured;
}
/// <summary>
/// 获取传入指定代理的最高值
/// </summary>
/// <param name="playerstats">所有玩家状态</param>
/// <param name="scoreDelegate">代理</param>
/// <returns></returns>
public static string GetPlayNameTopScore(PlayerStats[] playerstats, TopScoreDelegate scoreDelegate)
{
int bestScore = 0;
string name = "";
foreach (PlayerStats stats in playerstats)
{
int score = scoreDelegate(stats);
if (score > bestScore)
{
bestScore = score;
name = stats.name;
}
}
return name;
}
}
public class PlayStats
{
public static void Run()
{
PlayerStats[] playerStats = new PlayerStats[4];
for (int i = 0; i < playerStats.Length; i++)
{
playerStats[i] = new PlayerStats();
playerStats[i].deaths = i;
playerStats[i].kills = i;
playerStats[i].flagsCaptured = playerStats.Length - i;
playerStats[i].name = (i + 1).ToString();
}
// 在运行时候绑定了委托,让委托去返回需要的变量。这样可以减少很多的代码量
string mostKills =
DisplayPlayerNames.GetPlayNameTopScore(playerStats, DisplayPlayerNames.GetPlayStatsKills);
Console.WriteLine("最强杀手:{0}", mostKills);
string mostFlagsCaptured =
DisplayPlayerNames.GetPlayNameTopScore(playerStats, DisplayPlayerNames.GetPlayStatsFlagsCaptured);
Console.WriteLine("被捕次数最多的是:{0}", mostFlagsCaptured);
}
}
}
可能你还是会不理解为什么要用委托,虽然少了些代码,但是我用常规方法还是很香啊,简单易读。
为什么要用委托
它你减少代码量的同时还可以减少耦合。可能现在还不是很强烈这种对比。所以我们要让对比更加强烈,变为真香。
真香定律
using System;
namespace DelegatePro
{
/// <summary>
/// 玩家数据
/// </summary>
public class PlayerStats
{
public string name;
public int kills;
public int deaths;
public int flagsCaptured;
}
/// <summary>
/// 显示玩家数据
/// </summary>
public class DisplayPlayerNames
{
// 最高分数委托
public delegate int TopScoreDelegate(PlayerStats playerStats);
/// <summary>
/// 获取传入指定代理的最高值
/// </summary>
/// <param name="playerstats">所有玩家状态</param>
/// <param name="scoreDelegate">代理</param>
/// <returns></returns>
public static string GetPlayNameTopScore(PlayerStats[] playerstats, TopScoreDelegate scoreDelegate)
{
int bestScore = 0;
string name = "";
foreach (PlayerStats stats in playerstats)
{
int score = scoreDelegate(stats);
if (score > bestScore)
{
bestScore = score;
name = stats.name;
}
}
return name;
}
}
public class PlayStats
{
public static void Run()
{
PlayerStats[] playerStats = new PlayerStats[4];
for (int i = 0; i < playerStats.Length; i++)
{
playerStats[i] = new PlayerStats();
playerStats[i].deaths = i;
playerStats[i].kills = i;
playerStats[i].flagsCaptured = playerStats.Length - i;
playerStats[i].name = (i + 1).ToString();
}
// 更具优化的方法
// 使用lambda
/* 在这里使用,可以大大的减低耦合,你可以看到,我可以直接返回一个上面没有定义的方法-->死亡数量,基本上可以说,我可以随时添加我喜欢的
最高分数,而不用去添加过多的代码
*/
mostKills = DisplayPlayerNames.GetPlayNameTopScore(playerStats, stats => stats.kills);
Console.WriteLine("lambda->最强杀手:{0}", mostKills);
mostFlagsCaptured = DisplayPlayerNames.GetPlayNameTopScore(playerStats, stats => stats.flagsCaptured);
Console.WriteLine("lambda->被捕次数最多的是:{0}", mostFlagsCaptured);
string mostDeath = DisplayPlayerNames.GetPlayNameTopScore(playerStats, stats => stats.deaths);
Console.WriteLine("lambda->最多死亡次数的是:{0}", mostDeath);
}
}
}
香不香?运用Lambda之后都不用定义函数了,而且直接把大部分代码都删除了。虽然可读性有所减低,但是灵活性大大提高啊。这时某人可能会想,如果不用Lambda,委托也就那样啊。没事,我们接着看下面一篇。
最后
如果你还是没有明白为什么要用委托,推荐你马上去看下一篇。事件篇,这里委托的香处体现的淋漓尽致。