欢迎来到 IT实训基地-南通科迅教育
咨询电话:0513-81107100
C#编程:~你所了解的C#委托
2017/3/11
南通科迅教育
367
想在南通学java,有没有人推荐一下培训机构啊

C#委托的引入:

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

?
1
2
3
4
5
6
7
8
9
10
11
12
publicstaticvoidSayMyScores(intnumber)
{
    MathScore(number);
}
publicstaticvoidMathScore(intnumber)
{
    Console.WriteLine("Math:"+ number);
}
staticvoidMain(string[] args)
{
    Program.SayMyScores(60);
}

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publicstaticvoidSayMyScores(intnumber)
 {
     LanguageScore(number);
 }
 publicstaticvoidMathScore(intnumber)
 {
     Console.WriteLine("Math:"+ number);
 }
 publicstaticvoidLanguageScore(intnumber)
 {
     Console.WriteLine("Language:"+ number);
 }
 staticvoidMain(string[] args)
 {
     Program.SayMyScores(60);
 }
现在你也能够看出来了,这种方式的扩展性非常低。而且对于这种类似的需求,几乎是从头修改到尾。那么这种时候我们必须对此结构进行修改.或许你想的是使用if ~else 或者是switch 来优化:
?
1
2
3
4
5
6
7
8
9
10
11
12
enumSbuject
 {
     Langguage,
     Math
 }
 publicstaticvoidSayMyScores(intnumber,Sbuject sbu)
 {
     if(sbu == Sbuject.Langguage)
         LanguageScore(number);
     elseif(sbu == Sbuject.Math)
         MathScore(number);
 }

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

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

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

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

 

?
1
2
3
intans =0;
intnum1 =1;
intnum2 =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 就可以称作是:::一个委托!!!。(理解最重要,博主在这里用了点技巧,意思理解到位就行)。

 

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

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

 

?
1
publicdelegatevoidSubScore(intmumber);
然后将此委托类型作为MathScore 和LanguageScore函数的参数,最后执行即可。我们看完整的代码:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace CSharpProject
{
    publicdelegatevoidSubScore(intmumber);
    classProgram
    { 
        privatestaticvoidSayMyScores(intnumber,SubScore subScore)
        {
            subScore(number);
        }
        publicstaticvoidMathScore(intnumber)
        {
            Console.WriteLine("Math:"+ number);
        }
        publicstaticvoidLanguageScore(intnumber)
        {
            Console.WriteLine("Language:"+ number);
        }
        staticvoidMain(string[] args)
        {
            SayMyScores(60, MathScore);
            Console.ReadKey();
 
        }
    }
}
输出为:
Math:60

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

总结:

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

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

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


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

 

委托的相关操作:

1.定义委托类型:

?
1
delegatevoidSubScore(intmumber);
委托类型声明:

 

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

2.声明委托变量:

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

 

3.初始化委托变量:

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

1)通过new 运算符:

?
1
2
SubScore sub;
sub =newSubScore(Program.MathScore);
2)通过直接赋值:
?
1
2
3
SubScore sub;
sub =newSubScore(Program.MathScore);
sub = Program.LanguageScore;

4.赋值委托:

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

?
1
2
3
4
5
6
7
8
9
staticvoidMain(string[] args)
       {
           SubScore sub;
           sub =newSubScore(Program.MathScore);
           sub = Program.LanguageScore;
           sub(60);
           Console.ReadKey();
 
       }
输出为:

Math:60

 

5.组合委托:

委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表是两个操作数的委托调用列表的副本的连接。
委托是恒定的,操作数委托创建后不会被改变。委托组合拷贝的是操作数的副本。
?
1
2
3
4
5
6
7
SubScore sub1;
SubScore sub2;
SubScore sub3;
sub1 =newSubScore(Program.MathScore);
sub2 = Program.LanguageScore;
sub3 = sub1 + sub2;
sub3(61);
输出为:

Math:60

Language:60

 

 

6.委托的加减操作:

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

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

?
1
2
3
4
5
6
7
8
9
10
staticvoidMain(string[] args)
       {
           SubScore sub1;
          
           sub1 =newSubScore(Program.MathScore);
           sub1 += Program.LanguageScore;
           sub1(61);
           Console.ReadKey();
 
       }

此时输出:

Math:61

Language:60

此时我们删除MathScore方法:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
staticvoidMain(string[] args)
       {
           SubScore sub1;
          
           sub1 =newSubScore(Program.MathScore);
           sub1 += Program.LanguageScore;
           sub1(61);
           Console.WriteLine("删除后输出内容:");
              sub1 -= MathScore;
           sub1(60);
           Console.ReadKey();
 
       }

此时输出:

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

7.委托调用:

委托的调用和方法很是类似,委托调用后,调用列表中的每个方法都会被执行。但是在调用委托之前,应该判断下委托是否为空,如果委托为空的话会抛出异常。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
classProgram
    {
        publicdelegatevoidSubScore(intnumber);
        publicstaticvoidSayMyScores(intnumber,SubScore sub)
        {
            sub(number);
        }
        publicstaticvoidMathScore(intnumber)
        {
            Console.WriteLine("Math:"+ number);
        }
        publicstaticvoidLanguageScore(intnumber)
        {
            Console.WriteLine("Language:"+ number);
        }
        staticvoidMain(string[] args)
        {
            SubScore sub = MathScore;
            sub += LanguageScore;
            if(null!= sub)
            {
                sub(60);
            }
        }
    }
}

9.匿名方法:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    classProgram
    {
        publicdelegateintScore(intnumber);
        //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);
        //}
        staticvoidMain(string[] args)
        {
          
            Score myScore = delegate(intx)
            {
                returnx;
            };
           Console.WriteLine(myScore(1));
        }
    }
}

输出为:

1

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

这里我们实验一发:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
classProgram
   {
       publicdelegateintScore(intnumber);
       publicstaticintSay(intnumber)
       {
           Console.WriteLine("1111");
           return0;
       }
       
       staticvoidMain(string[] args)
       {
         
           Score myScore = delegate(intx)
           {
               returnx;
           };
           myScore = Program.Say;
          Console.WriteLine(myScore(1));
       }
   }

输出为:

1111

0

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

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

 

77
关闭
先学习,后交费申请表
每期5位名额
在线咨询
免费电话
QQ联系
先学习,后交费
TOP
您好,您想咨询哪门课程呢?
关于我们
机构简介
官方资讯
地理位置
联系我们
0513-91107100
周一至周六     8:30-21:00
微信扫我送教程
手机端访问
南通科迅教育信息咨询有限公司     苏ICP备15009282号     联系地址:江苏省南通市人民中路23-6号新亚大厦三楼             法律顾问:江苏瑞慈律师事务所     Copyright 2008-