C#中的委托

一.什么是委托

C#中的委托可以理解为对函数的包装,它使得C#中的函数可以作为参数被传递;委托的定义与方法的定义类似,只是在定义的前面多了一个delegate关键字,如下所示:

public delegate void MyDelegate(int para1, string para2);

委托能包装的方法是有一定限制的,例如能被前面的委托类型MyDelegate包装的方法需要满足以下条件:

(1).方法的返回类型必须为void;

(2).方法必须有两个参数,并且第一个参数应为int类型,第二个参数为string类型。

归纳起来,可以被委托包装的方法必须满足以下规则:

(1).方法的签名必须与委托一致,方法签名包括参数的个数、类型和顺序;

(2).方法的返回类型要和委托一致,注意,方法的返回类型不属于方法签名的一部分。

二.委托的使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
    class Program
    {
        //使用delegate关键字来定义一个委托类型
        public delegate void MyDelegate(int para1, int para2);
        static void Main(string[] args)
        {
            //声明委托变量d
            MyDelegate d;
            //实例化委托类型
            d = new MyDelegate(new Program().Add);
            //委托类型作为参数传递给另一个方法
            MyMethod(d);
            Console.ReadKey();
        }

        void Add(int para1, int para2)
        {
            int sum = para1 + para2;
            Console.WriteLine("两个数的和为:"+sum);
        }

        //方法的参数类型是委托类型
        private static void MyMethod(MyDelegate mydelegate)
        {
            //在方法中调用委托
            mydelegate(1, 2);
        }
    }
}

 三.委托的使用步骤

(1).定义委托类型:delegate void MyDelegate(type para1, type para2);其定义类似于方法的定义,只是多了一个delegate关键字;

(2).声明委托类型变量:MyDelegate d;既然委托是一种类型,那么可以使用委托来声明一个委托变量。

(3).实例化委托:d=new MyDelegate(obj.InstanceMethod);第二步只是声明了委托变量,但并没有将它实例化,类的实例化使用new关键字实现,而委托也属于类类型,所以委托的实例化也使用new关键字来进行,委托的实例化是用一个方法名(不能带左右括号)作为参数,并且该方法的定义必须符合委托的定义,即该方法的返回类型、参数个数和类型必须与委托定义中的一样。

(4).作为参数传递给方法:MyMethod(d);委托使得C#中,可以把一个方法作为另一个方法的参数,而委托可以看作是一个包装方法的对象。

(5).在方法中调用委托,MyMethod方法先调用委托,委托再调用方法InstanceMethod。

四.委托链的使用

C#中的委托也同样可以封装多个方法,C#中把封装多个方法的委托称作委托链或多路广播委托,且委托链中的方法的的返回值、参数类型,顺序也必须保持一致。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MultipleDelegate
{
    class Program
    {
        //声明一个委托类型
        public delegate void DelegateTest();
        static void Main(string[] args)
        {
            //用静态方法来实例化委托
            DelegateTest de1 = new DelegateTest(Program.method1);

            DelegateTest de2 = new DelegateTest(new Program().method2);

            //定义一个委托对象,一开始初始化为null,即不代表任何方法
            DelegateTest de = null;

            //使用“+”符号链接委托,链接多个委托后就成了委托链
            de += de1;
            de += de2;

            //调用委托链
            de();

            Console.ReadKey();
        }

        //静态方法
        private static void method1()
        {
            Console.WriteLine("这是静态方法");
        }

        //实例方法
        private void method2()
        {
            Console.WriteLine("这是实例方法");
        }

    }
}

五.从委托链中移除委托

既然能用“+”运算符把委托链接到一个委托对象实例上,自然也可以使用“-”运算符将某个委托从委托链对象上移除。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MultipleDelegate
{
    class Program
    {
        //声明一个委托类型
        public delegate void DelegateTest();
        static void Main(string[] args)
        {
            //用静态方法来实例化委托
            DelegateTest de1 = new DelegateTest(Program.method1);

            DelegateTest de2 = new DelegateTest(new Program().method2);

            //定义一个委托对象,一开始初始化为null,即不代表任何方法
            DelegateTest de = null;

            //使用“+”符号链接委托,链接多个委托后就成了委托链
            de += de1;
            de += de2;

            //使用“-”运算符把de1从委托链中移除
            de -= de1;

            //调用委托链
            de();

            Console.ReadKey();
        }

        //静态方法
        private static void method1()
        {
            Console.WriteLine("这是静态方法");
        }

        //实例方法
        private void method2()
        {
            Console.WriteLine("这是实例方法");
        }

    }
}

 六.匿名方法

匿名方法就是没有名称的方法,因为没有名字,匿名方法只能在函数定义的时候被调用,在其他任何情况下都不能被调用;而委托是用来包装方法的类类型,既然匿名方法也是方法,是可以被委托类型包装的。下面是用匿名方法的方式去实现前面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VoteDelegate
{
    public class Program
    {
        //定义委托
        delegate void Delegate(string name);
        static void Main(string[] args)
        {
           //使用匿名方法来实例化委托对象
            Delegate d = delegate(string name)
            {
                Console.WriteLine("姓名为:{0}", name);
            };
            d("张三");
            Console.ReadKey();
        }
        
    }
}

另外匿名方法也是有缺点的,不能被其他地方调用,即不具有复用性。匿名方法会自动形成"闭包",当一个外部函数包含对另一个内部函数的调用时,或当内部函数使用了外部函数的变量时,会形成闭包。闭包可能会延长外部变量的声明周期。

闭包演示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VoteDelegate
{
    public class Program
    {
       
        //定义闭包委托
        public delegate void Delegate();
        static void Main(string[] args)
        {
            Delegate d = CreateDelegate();
            d();

            Console.ReadKey();
        }

        //闭包延长变量的生命周期
        private static Delegate CreateDelegate()
        {
            //外部变量
            int count = 1;
            Delegate d = delegate()
            {
                Console.WriteLine(count);
                count++;
            };
            //调用委托
            d();

            return d;
        }
        
    }
}

打印结果:

上述代码中的变量count被匿名方法捕获后,它的生命周期会被延长,只要还有任何委托实例在引用它,那么它就一直存在,就不会在部分委托实例调用结束后被释放掉。

转载于:https://www.cnblogs.com/QingYiShouJiuRen/p/11150333.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值