服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 详解C#之委托

详解C#之委托

2022-09-09 14:15千金不如一默 C#

这篇文章主要介绍了C#委托的含义以及用法,文中代码非常详细,帮助大家更好的理解和学习

委托:顾名思义,让别人帮你办件事。委托是c#实现回调函数的一种机制。可能有人会问了,回调函数是个啥???

举个例子:我现在是一家公司的老板,公司现在在招聘.net工程师,我们有一个小姐姐专门负责接受求职者投递的简历,我就告诉这个小姐姐,一旦收到新的简历就转发给我一份。

这个例子里小姐姐要做的工作:给我转发一份简历(回调函数里的操作),就是一个回调函数的作用。一旦有了满足条件(收到了新的简历),小姐姐就会转发给我(触发回调函数

用来代码来看看是怎么实现的:

1.定义一个委托:

?
1
2
// 定义委托,这个委托需要获取一个int型参数,返回void
     internal delegate void feedback(int value);

 

2.定义回调方法:这里定义了两个方法,一个静态,一个实例。正好看看调用方式的不同。注意:定义的回调方法签名必须和委托对象一致(这里都是int 类型参数,没有返回值。这么说也不全对,涉及到协变逆变。这里就不解释这俩了),这是因为将方法绑定到委托时,编译器会检测他们的兼容性。不符合的话回报编译错误。就比如有一个方法要传入string类型,我们给它传递了一个int类型一样。

这里为了方便演示就只把数字打印在了控制台。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
       /// 静态回调方法
       /// </summary>
       /// <param name="value"></param>
       private static void feedbacktoconsole(int value)
       {
           // 依次打印数字
           console.writeline("item=" + value);
       }
       /// <summary>
       /// 实例回调方法
       /// </summary>
       /// <param name="value"></param>
       private void instancefeedbacktoconsole(int value)
       {
           console.writeline("item=" + value);
       }

 

3.编写一个方法来触发回调函数:有三个参数:前两个做循环使用,后一个接收定义的委托对象。内部代码循环调用回调方法 fb(val)的写法,其实就是相当于要调用的函数。例:

?
1
feedbacktoconsole(val)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// 使用此方法触发委托回调
/// </summary>
/// <param name="from">开始</param>
/// <param name="to">结束</param>
/// <param name="fb">委托引用</param>
private static void counter(int from,int to, feedback fb)
{
    for (int val = from; val <= to; val++)
    {
        // fb不为空,则调用回调方法
        if (fb != null)
        {
            fb(val);
        }
        //fb?.invoke(val); 简化版本调用
    }
}

4.定义counter的方法调用(这一步可有可无,为了区分静态和实例方法就写了)

第一次调用counter,传递null,在回调方法里有一步判空操作,所以是不回调用回调函数的。第二个counter调用正常传递参数,构造一个委托对象并绑定了一个方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
        /// 静态调用
        /// </summary>
        private static void staticdelegatedemo()
        {
            console.writeline("---------委托调用静态方法------------");
            counter(1, 10, null);
            counter(1, 10, new feedback(feedbacktoconsole));
            
            
 
        }
 
        /// <summary>
        /// 实例调用
        /// </summary>
        private static void instancedelegatedemo()
        {
            console.writeline("---------委托调用实例方法------------");
            program p = new program();
            counter(1, 10, null);
            counter(1, 5, new feedback(p.instancefeedbacktoconsole));
        }

 5. 查看控制台信息

完整代码:

?
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class program
   {
       // 定义委托,并引用一个方法,这个方法需要获取一个int型参数返回void
       internal delegate void feedback(int value);
       static void main(string[] args)
       {
         
           staticdelegatedemo();
           instancedelegatedemo();
           console.readkey();
       }
       
       /// <summary>
       /// 静态调用
       /// </summary>
       private static void staticdelegatedemo()
       {
           console.writeline("---------委托调用静态方法------------");
           counter(1, 10, null);
           counter(1, 10, new feedback(feedbacktoconsole));
          
 
       }
 
       /// <summary>
       /// 实例调用
       /// </summary>
       private static void instancedelegatedemo()
       {
           console.writeline("---------委托调用实例方法------------");
           program p = new program();
           counter(1, 10, null);
           counter(1, 5, new feedback(p.instancefeedbacktoconsole));
       }
 
 
       /// <summary>
       /// 静态回调方法
       /// </summary>
       /// <param name="value"></param>
       private static void feedbacktoconsole(int value)
       {
           // 依次打印数字
           console.writeline("item=" + value);
       }
       /// <summary>
       /// 实例回调方法
       /// </summary>
       /// <param name="value"></param>
       private void instancefeedbacktoconsole(int value)
       {
           console.writeline("item=" + value);
       }
   }

 

启动控制台:可以看到已经成功把数字打印出来了

详解C#之委托

6. 委托链:委托链是委托对象的集合。可以利用委托链调用集合中的委托所绑定的全部方法。继续在原有的基础上添加委托链的方法。

新添加的两个方法本质上没有区别都是对委托链的实现,不同的是写法,明显是第二个方法更加精简一些。这是因为c#编译器重载了+=和-=操作符,这两个操作符分别调用combine和remove。

?
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
28
29
30
31
32
33
34
35
/// <summary>
        /// 委托链调用 1
        /// </summary>
        /// <param name="p"></param>
        private static void chaindelegatedemo(program p)
        {
            console.writeline("---------委托链调用1------------");
            feedback fb1 = new feedback(feedbacktoconsole);
            feedback fb2 = new feedback(p.instancefeedbacktoconsole);
            feedback fbchain = null;
            fbchain = (feedback)delegate.combine(fbchain, fb1);
            fbchain = (feedback)delegate.combine(fbchain, fb2);
            counter(1, 3, fbchain);
            console.writeline();
            fbchain = (feedback)delegate.remove(fbchain, new feedback(feedbacktoconsole));
            counter(1, 3, fbchain);
        }
 
        /// <summary>
        /// 委托链调用 2
        /// </summary>
        /// <param name="p"></param>
        private  static void chaindelegatedemo2(program p)
        {
            console.writeline("---------委托链调用2------------");
            feedback fb1 = new feedback(feedbacktoconsole);
            feedback fb2 = new feedback(p.instancefeedbacktoconsole);
            feedback fbchain = null;
            fbchain += fb1;
            fbchain += fb2;
            counter(1, 3, fbchain);
            console.writeline();
            fbchain -= new feedback(feedbacktoconsole);
            counter(1, 2, fbchain);
        }

在main方法添加对委托链的调用:

?
1
2
3
4
5
6
7
8
9
10
static void main(string[] args)
       {
           program p = new program();
           staticdelegatedemo();
           instancedelegatedemo();
           chaindelegatedemo(p);
           chaindelegatedemo2(p);
           console.writeline("hello world!");
           console.readkey();
       }

启动项目:

详解C#之委托

7. c#为委托提供的简化:

7.1 不需要构造委托对象:

之前的代码:

counter(1, 10, new feedback(feedbacktoconsole));

构造了一个委托对象并传递给counter方法,由于c#编译器能自己推断。所以可以省略构造委托对象,直接传递方法。使代码的可读性更佳,也更容易理解。

简化后的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
/// <summary>
/// 静态调用
/// </summary>
private static void staticdelegatedemo()
{
    console.writeline("---------委托调用静态方法------------");
    counter(1, 10, null);
    //counter(1, 10, new feedback(feedbacktoconsole));
    counter(1, 10, feedbacktoconsole);
    
 
}

可以看到效果是一样的:

详解C#之委托

7.2 简化语法:不需要定义回调方法(以lambda表达式实现)

在前面的代码中定义了一个回调方法:

?
1
2
3
4
5
6
7
8
9
/// <summary>
/// 静态回调方法
/// </summary>
/// <param name="value"></param>
private static void feedbacktoconsole(int value)
{
    // 依次打印数字
    console.writeline("item=" + value);
}

现在以lambda表达式方式实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
/// <summary>
/// 静态调用
/// </summary>
private static void staticdelegatedemo()
{
    console.writeline("---------委托调用静态方法------------");
    counter(1, 10, null);
    //counter(1, 10, new feedback(feedbacktoconsole));
    //counter(1, 10, feedbacktoconsole);
    counter(1, 10, value => console.writeline(value));
 
}

lambda表达式实际上是一个匿名函数。编译器在看到lambda之后会在类中自动定义一个新的私有方法。类似于之前写的回调方法feedbacktoconsole()。lambda必须匹配委托!

lambda的语法: 参数 => 返回值。

=>左边是要传入的参数,本例中是传入一个int类型的变量,=>右边是具体的代码,相当于feedbacktoconsole(),{}中所做的操作

一些规则:

如果不传递参数: ()=>console.writeline("hello world!")

传递一个参数:(int n)=>console.writeline(n.tostring())    或者去掉()和int  编译器会自己推断类型:n=>console.writeline(n.tostring())

传递多个参数:(int n ,int m)=>console.writeline(n.tostring())  或者编译器自己推断类型:(n , m)=>console.writeline(n.tostring())

注:如果有一个方法需要多处调用或者方法里面的代码量较多。还是单独写一个方法较为理想。

最后看一下换成lambda的写法结果显示是否一样

详解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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class program
{
    // 定义委托,并引用一个方法,这个方法需要获取一个int型参数返回void
    internal delegate void feedback(int value);
    static void main(string[] args)
    {
        program p = new program();
        staticdelegatedemo();
        instancedelegatedemo();
        chaindelegatedemo(p);
        chaindelegatedemo2(p);
        console.writeline("hello world!");
        string[] names = { "jeff", "jee", "aa", "bb" };
        //char find = 'e';
        //names= array.findall(names, name => name.indexof(find) >= 0);
        //array.foreach(names, console.writeline);
        console.readkey();
    }
    
    /// <summary>
    /// 静态调用
    /// </summary>
    private static void staticdelegatedemo()
    {
        console.writeline("---------委托调用静态方法------------");
        counter(1, 10, null);
        //counter(1, 10, new feedback(feedbacktoconsole));
        //counter(1, 10, feedbacktoconsole);
        counter(1, 10, value => console.writeline(value));
 
    }
 
    /// <summary>
    /// 实例调用
    /// </summary>
    private static void instancedelegatedemo()
    {
        console.writeline("---------委托调用实例方法------------");
        program p = new program();
        counter(1, 10, null);
        counter(1, 5, new feedback(p.instancefeedbacktoconsole));
    }
 
    /// <summary>
    /// 委托链调用 1
    /// </summary>
    /// <param name="p"></param>
    private static void chaindelegatedemo(program p)
    {
        console.writeline("---------委托链调用1------------");
        feedback fb1 = new feedback(feedbacktoconsole);
        feedback fb2 = new feedback(p.instancefeedbacktoconsole);
        feedback fbchain = null;
        fbchain = (feedback)delegate.combine(fbchain, fb1);
        fbchain = (feedback)delegate.combine(fbchain, fb2);
        counter(1, 3, fbchain);
        console.writeline();
        fbchain = (feedback)delegate.remove(fbchain, new feedback(feedbacktoconsole));
        counter(1, 3, fbchain);
    }
 
    /// <summary>
    /// 委托链调用 2
    /// </summary>
    /// <param name="p"></param>
    private  static void chaindelegatedemo2(program p)
    {
        console.writeline("---------委托链调用2------------");
        feedback fb1 = new feedback(feedbacktoconsole);
        feedback fb2 = new feedback(p.instancefeedbacktoconsole);
        feedback fbchain = null;
        fbchain += fb1;
        fbchain += fb2;
        counter(1, 3, fbchain);
        console.writeline();
        fbchain -= new feedback(feedbacktoconsole);
        counter(1, 2, fbchain);
    }
    /// <summary>
    /// 使用此方法触发委托回调
    /// </summary>
    /// <param name="from">开始</param>
    /// <param name="to">结束</param>
    /// <param name="fb">委托引用</param>
    private static void counter(int from,int to, feedback fb)
    {
        for (int val = from; val <= to; val++)
        {
            // fb不为空,则调用回调方法
            if (fb != null)
            {
                fb(val);
            }
            //fb?.invoke(val); 简化版本调用
        }
    }
 
    /// <summary>
    /// 静态回调方法
    /// </summary>
    /// <param name="value"></param>
    private static void feedbacktoconsole(int value)
    {
        // 依次打印数字
        console.writeline("item=" + value);
    }
    /// <summary>
    /// 实例回调方法
    /// </summary>
    /// <param name="value"></param>
    private void instancefeedbacktoconsole(int value)
    {
        console.writeline("item=" + value);
    }
}

 

github:

https://github.com/xiaomaprincess/csharp

以上就是详解C#之委托的详细内容,更多关于C#之委托的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/jixiaosa/p/10687068.html

延伸 · 阅读

精彩推荐
  • C#C#中try...catch的使用与常见面试题分享

    C#中try...catch的使用与常见面试题分享

    这篇文章首先给大家介绍了关于C#中try...catch的语法,而后又给大家分享了关于C#中try...catch最常见的面试题,具有一定的参考借鉴价值,需要的朋友们下面...

    wolfy10692021-12-27
  • C#c# 两个数组比较,将重复部分去掉,返回不重复部分的实现

    c# 两个数组比较,将重复部分去掉,返回不重复部分的实现

    下面小编就为大家带来一篇c# 两个数组比较,将重复部分去掉,返回不重复部分的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一...

    C#教程网10352021-12-14
  • C#再来说说我喜欢的 Dotnet 5.0 & C# 9

    再来说说我喜欢的 Dotnet 5.0 & C# 9

    语言方面,最主要的特性,是 Record。这是 C# 9 出来的一个新数据类型。没错,Record 是一个数据类型。...

    老王Plus11622021-09-29
  • C#浅谈C# AOP的简单实现

    浅谈C# AOP的简单实现

    这篇文章主要介绍了浅谈C# AOP的简单实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    懒得安分7732022-02-25
  • C#C#实现ini文件读写操作

    C#实现ini文件读写操作

    这篇文章主要为大家详细介绍了C#实现ini文件的读写操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    壹号知识搬运工3952022-02-28
  • C#unity实现透明水波纹扭曲

    unity实现透明水波纹扭曲

    这篇文章主要为大家详细介绍了unity实现透明水波纹扭曲,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    请输入姓名5512022-09-06
  • C#C#登入实例

    C#登入实例

    本篇文章通过截图的方式向大家展示C#程序登陆实现的全过程,利用了C#三层架构的编写方法,希望对大家今后编写代码有所帮助...

    sctnl5842021-12-10
  • C#C#图像亮度调式与伪彩色图的处理教程(推荐)

    C#图像亮度调式与伪彩色图的处理教程(推荐)

    下面小编就为大家推荐一篇C#图像亮度调式与伪彩色图的处理教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    Yulong57594962022-02-13