从奇葩的角度看委托

说明:本文灵感来自直面曹大版主直击语言本质的震撼(http://bbs.csdn.net/topics/390622815),所以摘抄了不少版主的原话

委托

委托是C#提出的一套独有的机制,它封装了一种结构,能够将方法当作参数传入其他函数,它能让一个函数可以实现总体流程的复用,同时让调用者“填空”,自定义某个细节。而一般的函数,则只能复用功能本身。

比如我写了这样一个函数

private void Show(int numA,int numB)
        {
            Console.WriteLine(numA + numB);
        }

它能够输出1+2的值,现在想要写计算器了,光输出一个加不够,现在最少还要减法,那么再写一个

  private void Show_Subtract(int numA,int numB)
        {
            Console.WriteLine(numA - numB);
        }

类似的还有乘法,除法,所以我要依次去写四种输出方法,如果以后还要再增加具体操作的话,再继续增加方法,比如开平方根,求幂等等。

这么多的同类型方法放在客户端被调用(对于客户端做展示而言,抽象成‘输出’操作)会显得非常难以管理维护以及不安全,在委托特性尚未发布之前,我们处理类似情况的时候也有其他多种途径,设计模式是个非常不错的选择,所以我们引入了一些设计模式来帮助我们管理这些操作方法,代码结构如下(设计模式不是主要讲的内容,感兴趣推荐一本书《大话设计模式》)。

在委托出现之前

提供一个统一的接口,开放给外部调用

abstract class OperationBase
    {
        //禁止直接给NumA,NumB赋值,由外部传递参数进来,确保封装的安全性
        public int NumA { get; private set; }
        public int NumB { get; private set; }

        public OperationBase(int numA, int numB) 
        {
            NumA = numA;
            NumB = numB;
        }

        /// <summary>
        /// 每一个计算器(操作)都需要返回值,由具体操作决定
        /// </summary>
        /// <returns></returns>
        public abstract double GetResult();
}

为不同的操作去实现内容

加法操作
class Add : OperationBase
    {
        public Add(int numA, int numB)
            : base(numA, numB)
        {
        }

        public override double GetResult()
        {
            return NumA + NumB;
        }
    }
减法操作
class Subtract : OperationBase
    {
        public Subtract(int numA, int numB)
            : base(numA, numB)
        { }

        public override double GetResult()
        {
            return NumA - NumB;
        }
    }

具体调用:
private static void Show(OperationBase op)
        {
            //真正实现操作的不是op自己,而是实现其操作本身的实例
            Console.WriteLine("利用设计模式来管理同一类型的操作,{0} {1} {2}={3}", op.NumA, op.GetType().Name, op.NumB, op.GetResult());
            Console.ReadLine();
        }

static void Main(string[] args)
        {
            //在这里传入了操作的实例对象
            Show(new Add(1, 2));
        }

运行后输出1 And 2 = 3

这样简单封装了一下之后,客户端的压力减轻了,只需要进行一个操作(输出),把其中的实现过程隐藏好了,这样我们直需要使用对象就可以能够实现,这更加符合面向对象设计。

而在委托出现之后,我们可以这样做:

//首先写好一些操作
class Operation
    {
        public double Add(int numA, int numB) 
        {
            return numA + numB;
        }
        public double Decrease(int numA, int numB)
        {
            return numA - numB;
        }
        public double Multipy(int numA, int numB)
        {
            return numA * numB;
        }
        public double Divide(int numA, int numB)
        {
            if(numB == 0)
                throw new InvalidOperationException();
            return numA / numB;
        }
    }

接着就能直接在客户端调用

//首先声明委托
private delegate double OperationDelegate(int numA, int numB);
static void Main(string[] args)
        {
OperationDelegate opd = new Operation().Add;
            //在这里传入了操作的实例对象
            Show(1, 2, opd);
            //比较上面的委托方法,从表象看它只是把参数放在了外面传入,再传入一个delegate
            Show(new Add(1, 2));
        }
略改变输出方法:
private static void Show(int numA, int numB, OperationDelegate opd)
        {
            //真正实现操作的方法被当做参数传入了
            Console.WriteLine("利用委托直接传入方法\n{0}{1}{2}={3}", numA, opd(numA, numB).GetType().Name, numB, opd(numA, numB));
            Console.ReadLine();
        }

整个过程中,我们省略了之前一大串为设计模式而准备的代码(内容),在这里的表象显示了它不用再为每个操作方法写一个类,也不用每次都再实例化类,一个操作(operation)实例,全局搞定实际操作(Add,Substract)。

而在匿名方法出现后,更加简化了委托调用方法的方式:


 static void Main(string[] args)
        {
OperationDelegate opd = new Operation().Add;
            //在这里传入了操作的实例对象
            Show(1, 2,opd); 
            //匿名函数的委托,轻小简便甚至不用声明方法体,但方法内容过长会降低可读性。
            Show(1, 2, (x, y) => { return x + y; }  );

            //比较上面的委托方法,从表象看它只是把参数放在了外面传入,再传入一个delegate
            Show(new Add(1, 2));
        }

注意:我们没有声明新的Show方法,同样还是同一个方法,

当然,使用了用泛型参数我们更加能看明白:

private static void Show(int numA, int numB, Func<int, int, double> func)
        {
            //真正实现操作的方法由泛型参数传入
            Console.WriteLine("利用泛型委托传入方法\n{0}{1}{2}={3}", numA, func(numA, numB).GetType().Name, numB, func(numA, numB));
            Console.ReadLine();
        }

        static void Main(string[] args)
        {
            //比较之后一眼就能看出,两者之间唯一的差距就是参数传入的顺序问题!(夸张)
            Show(1, 2, new Operation().Add);
            Show(new Add(1, 2));
        }


由此可见:

其实程序的本质就是算法+数据结构,而委托是一种由.net封装好的数据结构。委托定义好了它的内部操作,让方法能被当作参数传入其他函数,能让一个函数可以实现总体流程的复用,是让调用者“填空”(选择方法),自定义某个细节,让有类似操作的一系列方法进行复用。

从某种程度上来说,委托的思路其实就是一种设计模式,它的目的如上所述。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值