C#编程之你所了解的C#委托
Vivian 2018-05-22 来源 : 阅读 1233 评论 0

摘要:我是一个C++的铁杆粉丝,但是现在还是一个正在学习C++ 的小白。因为毕业后想搞游戏开发,所用的引擎是Unity,所以不得不好好学习C#编程。我在从C++ 转而学习C#时,遇到的第一个问题就是C#编程中的委托和事件。(我认为C# 的委托特别像C++ 中的函数指针,但是比函数指针要强大)。接下来就让我们一起来看看吧。

前言:

我是一个C++的铁杆粉丝,但是现在还是一个正在学习C++ 的小白。因为毕业后想搞游戏开发,所用的引擎是Unity,所以不得不好好学习C#编程。我在从C++ 转而学习C#时,遇到的第一个问题就是C#编程中的委托和事件。(我认为C# 的委托特别像C++ 中的函数指针,但是比函数指针要强大)。接下来就让我们一起来看看吧。本篇博文我将会详细讲解什么是C# 的委托,以及关于C# 委托的相关常用操作方法。

C#委托的引入:

在中国的传统教育中,考试成绩被认为是可以判断一个学生的优秀程度。现在初中生小明回到家里,家里人问他数学考了多少(可怜的小明刚好及格),于是小明告诉了家里数学考了多少分:

   

public static void SayMyScores(int number)
{
    MathScore(number);
}
public static void MathScore(int number)
{
    Console.WriteLine("Math:" + number);
}
static void Main(string[] args)
{
    Program.SayMyScores(60);
}

   


然后家里人问他语文考了多少,那么针对上个程序的问题来了:

我们能做的是再写一个函数,然后修改SayScores函数:(不幸运的是小明的语文也是60分)

   

public static void SayMyScores(int number)
 {
     LanguageScore(number);
 }
 public static void MathScore(int number)
 {
     Console.WriteLine("Math:" + number);
 }
 public static void LanguageScore(int number)
 {
     Console.WriteLine("Language:" + number);
 }
 static void Main(string[] args)
 {
     Program.SayMyScores(60);
 }

   

现在你也能够看出来了,这种方式的扩展性非常低。而且对于这种类似的需求,几乎是从头修改到尾。那么这种时候我们必须对此结构进行修改.或许你想的是使用if ~else 或者是switch 来优化:


enum Sbuject
 {
     Langguage,
     Math
 }
 public static void SayMyScores(int number,Sbuject sbu)
 {
     if (sbu == Sbuject.Langguage)
         LanguageScore(number);
     else if (sbu == Sbuject.Math)
         MathScore(number);
 }

   


但是这种方式是绝对不可取的。
原因有很多:比如:如果当学科较多时,你的if -else 或者是switch要写多长?这种方式很不利于扩展和代码的维护。

那么我们应该采取怎样的方式呢?

或者你可以这样考虑:如果我们在函数中,让第二个代表一种参数变量,这种变量,当将MathScore赋值给次变量时,那么这个变量就代表了MathScore方法;当将LanguageScore 赋值给该参数变量时,该变量代表的就是LanguageScore方法。那么当我们执行该参数变量时,就是在执行MathScore 或者LanguageScore方法。

我们来观察一下这两个有些类似的函数。首先返回类型的是:void ,参数是int 和枚举类型。我们先看这里:

   

int ans = 0;
int num1 = 1;
int num2 = 2;

   

 

如果我们让ans = num1,那么ans 就是1,如果让ans = num2 ,那么ans 就是2。从这里,我们可以想到一种方式:我们用X(没错,就是字母X ) 类比ans ,num1 和num2 分别类比MathScore 和LanguageScore方法。如果X = MathScore() 函数(MathScore 函数类比为num 1 ),那么X 就表示MathScore 函数;如果X = LanguageScore() 函数,那么X 就表示是LanguageScore函数了。那么我们如果执行了X,最后得到的结果就是我们想要执行的函数所显示的结果了。

那么此时这个X 就可以称作是:::一个委托!!!。(理解最重要,博主在这里用了点技巧,意思理解到位就行)。

 

那么我们根据上面的案例接着做:

首先我们需要一个委托,用于处理某个科目的函数或者多个科目函数的调用。


public delegate void SubScore(int mumber);

   

然后将此委托类型作为MathScore 和LanguageScore函数的参数,最后执行即可。我们看完整的代码:


namespace CSharpProject
{
    public delegate void SubScore(int mumber);
    class Program
    { 
        private static void SayMyScores(int number,SubScore subScore)
        {
            subScore(number);
        }
        public static void MathScore(int number)
        {
            Console.WriteLine("Math:" + number);
        }
        public static void LanguageScore(int number)
        {
            Console.WriteLine("Language:" + number);
        }
        static void Main(string[] args)
        {
            SayMyScores(60, MathScore);
            Console.ReadKey();
 
        }
    }
}

   

输出为:
Math:60

现在你已经对委托有了最简单最基础的了解了。那么我们在此总结下:

总结:

委托作为C#中的一个非常重要的概念是必须要掌握的。那么委托到底是什么呢?从数据结构层次来说,委托可以看做是一种用户自定义的类型。这种类型是专门处理具有相同签名和返回类型的。从设计的层次来讲,委托提供了方法的抽象。学过面向对象的应该可以理解这段话。

我认为,委托为一种类型,它是定义方法的类型,这样使得方法可以作为参数来进行传递。这种方式,很好的避免了代码中判断过多而且这种方式具有很好的扩展性。

那么委托既然可以作为一种类型,那么这种类型到底存储的是什么呢?简单理解:存储了具有相同签名和返回类型的方法的地址(跟C++的函数指针很是相似)。


ok,委托的概念已经将清楚了,下面就说下

 

委托的相关操作:

1.定义委托类型:


delegate void SubScore(int mumber);

   

委托类型声明:

 

delegate类型(公有|私有|保护) + delegate + 返回类型 + 函数名(函数参数);

2.声明委托变量:


SubScore sub;

   

这里:委托既然可以看做是一种类型,那么我们就可以根据类变量的声明来进行,跟:int number 类似。

 

3.初始化委托变量:

初始化委托变量常用的有两种方式:

1)通过new 运算符:

   

SubScore sub;
sub = new SubScore(Program.MathScore);

   

2)通过直接赋值:


SubScore sub;
sub = new SubScore(Program.MathScore);
sub = Program.LanguageScore;

   

 

4.赋值委托:

需要注意的一点是委托是一种引用类型,那么我们可以直接将方法赋给它,然后如果你赋了很多方法,那么它只会引用最后赋值的方法,而对于其他的方法会被回收器回收:


static void Main(string[] args)
       {
           SubScore sub;
           sub = new SubScore(Program.MathScore);
           sub = Program.LanguageScore;
           sub(60);
           Console.ReadKey();
 
       }

   

输出为:

Math:60

 

5.组合委托:

委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表是两个操作数的委托调用列表的副本的连接。
委托是恒定的,操作数委托创建后不会被改变。委托组合拷贝的是操作数的副本。


SubScore sub1;
SubScore sub2;
SubScore sub3;
sub1 = new SubScore(Program.MathScore);
sub2 = Program.LanguageScore;
sub3 = sub1 + sub2;
sub3(61);

   

输出为:

Math:60

Language:60

 

 

6.委托的加减操作:

委托有时候可以看作是一种方法的数组,这样,我们就可以往数组里添加函数或者是删除函数:

利用加法可以让一个委托变量指向多个方法,那么当我们调用时,会顺序的调用委托所引用的所有方法
利用减法何以在指向的多个方法中删除某种方法:


static void Main(string[] args)
       {
           SubScore sub1;
          
           sub1 = new SubScore(Program.MathScore);
           sub1 += Program.LanguageScore;
           sub1(61);
           Console.ReadKey();
 
       }

   


此时输出:

Math:61

Language:60

此时我们删除MathScore方法:


static void Main(string[] args)
       {
           SubScore sub1;
          
           sub1 = new SubScore(Program.MathScore);
           sub1 += Program.LanguageScore;
           sub1(61);
           Console.WriteLine("删除后输出内容:");
              sub1 -= MathScore;
           sub1(60);
           Console.ReadKey();
 
       }

   

 

此时输出:

Math:61
Language:61
删除后输出内容:
Language:60
 

7.委托调用:

委托的调用和方法很是类似,委托调用后,调用列表中的每个方法都会被执行。但是在调用委托之前,应该判断下委托是否为空,如果委托为空的话会抛出异常。


class Program
    {
        public delegate void SubScore(int number);
        public static void SayMyScores(int number,SubScore sub)
        {
            sub(number);
        }
        public static void MathScore(int number)
        {
            Console.WriteLine("Math:" + number);
        }
        public static void LanguageScore(int number)
        {
            Console.WriteLine("Language:" + number);
        }
        static void Main(string[] args)
        {
            SubScore sub = MathScore;
            sub += LanguageScore;
            if(null != sub)
            {
                sub(60);
            }
        }
    }
}

   

 

9.匿名方法:

匿名方法经常跟Lamabda结合使用,首先我简单先说下匿名方法(我会在最近更新一篇关于C#匿名方法的文章):

一般来说:在初始化委托时,可以内联一个方法,这个方法就是匿名方法:
如:


    class Program
    {
        public delegate int Score(int number);
        //public delegate void SubScore(int number);
        //public static void SayMyScores(int number,SubScore sub)
        //{
        //    sub(number);
        //}
        //public static void MathScore(int number)
        //{
        //    Console.WriteLine("Math:" + number);
        //}
        //public static void LanguageScore(int number)
        //{
        //    Console.WriteLine("Language:" + number);
        //}
        static void Main(string[] args)
        {
          
            Score myScore = delegate(int x)
            {
                return x;
            };
           Console.WriteLine(myScore(1));
        }
    }
}

   


输出为:

1

而当myScore 引用了其他的方法后,会发生什么呢?

这里我们实验一发:


class Program
   {
       public delegate int Score(int number);
       public static int Say(int number)
       {
           Console.WriteLine("1111");
           return 0;
       }
       
       static void Main(string[] args)
       {
         
           Score myScore = delegate(int x)
           {
               return x;
           };
           myScore = Program.Say;
          Console.WriteLine(myScore(1));
       }
   }

   


输出为:

1111

0

看到这里就明白:会先调用引用的方法,然后调用本身的匿名方法。

关于委托还有很多重要的内容,这里就不一一列举了。等自己用熟练了,有了自己的深刻理解之后再分享给大家。

本文由职坐标整理并发布,了解更多内容,请关注职坐标编程语言C#.NET频道!

本文由 @Vivian 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程