C# 委托与事件-委托篇

请按照顺序阅读

委托(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,委托也就那样啊。没事,我们接着看下面一篇。

最后

如果你还是没有明白为什么要用委托,推荐你马上去看下一篇。事件篇,这里委托的香处体现的淋漓尽致。

猜你喜欢

转载自blog.csdn.net/qq448545478/article/details/106745286