浅谈C#委托

委托:

当要把方法传递给其他方法时,就需要使用委托。也就是把方法作为参数来传递。

委托是一种特殊的类型对象,其特殊在于我们定义的所有对象都包含数据,而委托包含的只是一个或多个方法的地址。

委托的一个特征是它们类型是安全的,可以确保调用的方法的签名是正确的。既可以调用对象的实例方法,也可以调用静态方法,只要方法的签名和委托的签名一致就行。

自定义委托:

示例:

using System;

namespace ConsoleApp
{
    // 声明一个委托 参数double 返回值double
    delegate double DoubleOp(double x);
    class Program
    {
        static void Main(string[] args)
        {
            // 1、使用new关键字
            DoubleOp op = new DoubleOp(Action1);
            Console.WriteLine(op(4));   // 8

            // 2、直接复制 (称为委托推断)
            DoubleOp op1 = Action2;
            Console.WriteLine(op1.Invoke(4));   // 16

            // 说明:
            // op(4) 和 op1.Invoke(4)
            // 直接使用()和使用委托类的Invoke()方法作用完全相同;
            // 使用op1.Invoke(4)底层编译器也会转换为 op1();

            Console.Read();
        }

        static double Action1(double val)
        {
            return val * 2;
        }

        static double Action2(double val)
        {
            return val * val;
        }
    }
}

泛型委托:

Action<T>和Func<T>

除了使用自定义的委托之外,还可以使用Action<T>和Func<T>泛型委托。

Action<T>:

引用一个无返回类型的方法,可以传递0到16种不同的参数类型。没有泛型参数的Action类可以调用没有参数的方法;

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Action   调用无参数的方法
            // Action<T>   调用1个参数的方法
            // Action<T1, T2>   调用2个参数的方法
            // Action<T1, T2, ..., T16>   调用16个参数的方法
            // 示例:
            Action action = Action;
            action();
            Action<string> action1 = Action1;
            action1("");
            Action<string, string> action2 = Action2;
            action2("", "");

            Console.Read();
        }

        static void Action()
        {
            Console.WriteLine("Action");
        }

        static void Action1(string val)
        {
            Console.WriteLine("Action1");
        }

        static void Action2(string val1, string val2)
        {
            Console.WriteLine("Action2");
        }
    }
}

Func<T>:

允许调用带返回类型的方法,同样也支持0到16种参数类型。

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Func<out T>;  调用带返回类型的无参方法
            // Func<in T1, in T2, out T>;   调用2个带参数方法
            // Func<in T1, in T2,..., in T16, out T>;   调用16个带参数方法
            // out T返回类型
            // 示例:
            Func<double, double> func1 = Action1;
            Console.WriteLine(func1(4));   // 8

            Func<int, double, double> func2 = Action2;
            Console.WriteLine(func2(4, 2.2));   // 8.8

            Console.Read();
        }

        static double Action1(double val)
        {
            return val * 2;
        }

        static double Action2(int val1, double val2)
        {
            return val1 * val2;
        }
    }
}

多播委托:

前面使用的委托都只包含一个方法的调用,调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要显示的调用多次委托。

委托也可以包含多个方法,这种委托就称为多播委托。多播委托按顺序连续调用多个方法,因此,委托的签名就必须返回void;否则,就只能得到最后一个方法的结果。

语法很简单,使用运算符+和+=(增加委托的方法调用) 或者 -和-= (删除委托的方法调用);

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // 增加委托的方法调用
            Action<double> actions = Action1;
            actions += Action2;
            actions(4);

            // 删除委托的方法调用
            actions -= Action2;

            Console.Read();
        }

        static void Action1(double val)
        {
            Console.WriteLine(val *2);
        }

        static void Action2(double val)
        {
            Console.WriteLine(val * val);
        }
    }
}

多番委托可能导致的问题,如果委托调用的其中一个方法抛出异常,结果会怎么样?

运行代码:

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Action<double> actions = Action1;
            actions += Action2;
            try
            {
                actions(4);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }

        static void Action1(double val)
        {
            Console.WriteLine(val * 2);
            // 抛出异常
            throw new Exception("Error in Actoin1");
        }

        static void Action2(double val)
        {
            Console.WriteLine(val * val);
        }
    }
}

结果:

8
Error in Actoin1

由此得知:其中一个方法抛出异常,则整个迭代就会停止。

在这种情况下,为了避免该问题,可以使用Delegate类定义的GetInvocationList()方法自己迭代方法列表。

匿名方法:

要想使委托正常工作,方法就必须存在,但还有另一种使用委托的方式,就是通过匿名方法。

用匿名方法定义委托与前面的定义其实并没有什么区别,只是简化了代码,运行速度并没有加快,底层编译器仍然定义了一个方法,只是该方法名称由编译器自动指定。

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // 示例:
            // 使用delegate关键字
            Action<string> action1 = delegate (string param)
            {
                Console.WriteLine("Action1");
            };
            action1("");

            // 简化 使用Lambda表达式
            Action<string> action2 = (string param) =>
            {
                Console.WriteLine("Action2");
            };
            action2("");

            Console.Read();
        }
    }
}

需要注意的是,使用匿名方法必须遵守两条规则:

1、在匿名方法中不能使用跳转语句(break、goto、continue)跳转到该匿名方法的外部,同样,方法外部的跳转语句也不能跳转到该匿名方法内部。

2、在匿名方法内部不能访问不安全的代码,也不能访问匿名方法外部使用的ref和out参数。

原文地址:https://www.cnblogs.com/sokarl/p/11788699.html

时间: 2024-10-15 09:58:27

浅谈C#委托的相关文章

浅谈 C#委托

看了<CLR via C#>的17章委托后,为自己做一点浅显的总结,也分享给需要的人. .NET通过委托来提供一种回调函数机制,.NET委托提供了很多功能,例如确保回调方法是类型安全的(CLR重要目标).委托好允许顺序调用多个方法(委托链),并且支持调用静态方法和实例方法. 委托的基本语法就不多说了. internal delegate void Feedback(int value); public sealed class Program{ publick static void Main

小兵 浅谈C#委托&lt;delegate&gt;

最近处于面试找工作的阶段,面试中遇到这个问题已经多次,一直想了解,就趁这个机会好好梳理一下啊. 当提及委托,大多数人第一印象是它相当于C++的函数指针,可以将方法作为参数进行传递,也可以达到函数回调的作用. 委托例子:其实在生活中也有很多这样的例子,例如我们打官司,首先应该找到律师,委托律师去帮我们打官司,这就是委托.在程序中我们可以针对这个例子这样写: 1.首先定义一个委托:public delegate void Lawyer(string matter)   //相当于律师这个角色 2.再

浅谈C#委托和事件(转载)

委托给了C#操作函数的灵活性,我们可使用委托像操作变量一样来操作函数,其实这个功能并不是C#的首创,早在C++时代就有函数指针这一说法,而在我看来委托就是C#的函数指针,首先先简要的介绍一下委托的基本知识: 委托的定义委托的声明原型是 delegate <函数返回类型> <委托名> (<函数参数>)例子:public delegate void CheckDelegate(int number);//定义了一个委托CheckDelegate,它可以注册返回void类型且

浅谈C#委托的用法-delegate[转]

一.委托的概念 委托和类一样是一种用户自定义类型,它存储的就是一系列具有相同签名和返回类型的方法的地址,调用委托的时候,它所包含的所有方法都会被执行. 借用百度上的一句话概括:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法, 可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性. 二.委托的声明 与对应的方法具有相同的参数类型.参数个数.返回值.通俗来讲就是“函数的模板原型”. 三.委托的使用

浅谈委托和事件(一)

浅谈委托和事件(一) 关于委托和事件,可能是.NET或者说是面向对象编程语言中的一个比较重要又比较难以理解的概念.关于这一话题,园子里的人也写了很多文章,最经典的可能就是张子阳的C#中的委托和事件这两篇文章了,之前也看过MSDN 上的WebCast深入 "委托和事件".可能和很多人一样,刚开始读的时候,觉得很清楚,但是过了一段时间好像又忘记了委托和事件的区别,知道很久以前,在一次面试中我被问到委托和事件有什么区别,一下子就说不清了. 所以这里稍微理一下,也算是自己的一个总结.当然,还是

浅谈ThreadPool 线程池(引用)

出自:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html 浅谈ThreadPool 线程池 相关概念: 线程池可以看做容纳线程的容器: 一个应用程序最多只能有一个线程池: ThreadPool静态类通过QueueUserWorkItem()方法将工作函数排入线程池: 每排入一个工作函数,就相当于请求创建一个线程: 线程池的作用: 线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程

浅谈Kotlin(三):类

浅谈Kotlin(一):简介及Android Studio中配置 浅谈Kotlin(二):基本类型.基本语法.代码风格 前言: 已经学习了前两篇文章,对Kotlin有了一个基本的认识,往后的文章开始深入介绍Kotlin的实战使用. 本篇介绍Kotlin中类的使用. 一.表现形式 首先看一段Java中定义类的形式,定义三个属性,每一个属性对应一个get.set方法,有一个toString()方法 /* * @author xqx * @emil [email protected] * create

浅谈产业界与学术界的合作研究(转)

[编者注:原文可参阅: http://blog.sciencenet.cn/blog-414166-795432.html ] 最近网络上有一个流传甚广的微故事:"某企业引进了一条香皂包装线,结果发现经常会有空盒流过.厂长聘请一个博士后花了200 万设计出一个全自动分检系统.一个乡镇企业遇到了同样的问题,民工花90 元买了一台大电扇放在生产线旁,一有空盒经过便会吹走."这个微故事不断出现在笔者的视线中,想必在网络上得到了公众的认可.引起了共鸣,所以大家争相转发.平心而论,大多数人的内心

浅谈 GetHashCode

我们知道,System.Object 类是 .NET Framework 中所有类的最终基类,它是类型层次结构的根,并为派生类提供低级别服务.通常不要求类声明从 Object 的继承,因为继承是隐式的.因为 .NET Framework 中的所有类均从 Object 派生,所以 Object 类中定义的每个方法可用于系统中的所有对象.派生类可以而且确实重写这些方法中的某些,其中包括: Equals - 支持对象间的比较. Finalize - 在自动回收对象之前执行清理操作. GetHashCo