学习委托笔记

       最近一直在想如何解释委托,比如一个婚姻律师事务所,他处理婚姻相关的案子,这些案子的共同点都属于婚姻调解类别,不同点就是各个案子的当事人不一样,案子处理的方式不一样.这和委托有什么关系呢,这个例子里面,我们可以把婚姻律师事务所当作一个委托,而针对每个不同当事人处理方式不一样,我们可以理解为具体实现的不同函数.简单来说,事务所为委托,只要与其签名(返回值和参数)相同的函数都可以挂在这个委托下来调用,上面的婚姻自然可以理解为事务所的标签.

为什么要引入委托?

首先我们来看看一个小场景.

经理有四个秘书,分管不同业务,经理办公室有一电话,设定按键1接通秘书1,按键2接通秘书2........

我们有以下代码:

 

void 接秘书1()
{
      //其他代码
      秘书1.是否接通=接通状态;
}

void 接秘书2()
{
      //其他代码
      秘书2.是否接通=接通状态;
}

void 经理电话()
{
    if(按键==1)
    {
         接秘书1();
    }
    if(按键==2)
    {
         接秘书2();
    }
}

从上面简易代码中,我们看到接秘书1()和接秘书2()代码中的注释"其他代码"应该是相同的代码,获取她们可以提取到经理电话()方法的最上端以精简代码.但如果碰到foreach一类的代码,这种迁移自然是不明智的.现在要把//其他代码部分抽离出来,让其和具体业务形式分离开来,即抽象出来.

void 接秘书1()
{
    秘书1.是否接通=接通状态;
}

void 接秘书2()
{
    秘书2.是否接通=接通状态;
}

void dosomething(接秘书 jms)
{
    //其他代码
     接秘书();
}

如上,dosomething()方法中有可以抽离的代码,但需要一个接秘书()的方法,这个方法可以代表接秘书1(),接秘书2()等多个方法.那现在就涉及到委托,委托为引用类型,是一个类,她定义了方法类型,如同string定义一个字符串a,而a可以被当作函数参数来传递,而委托delegate也可以定义一个类型b,而b同样也可以作为函数参数来传递.说到这里,上面代码中,我们只需要声明一个接秘书()方法的委托即可代表一系列此类方法.

public delegate void 接秘书();

而我们只需要指定进入dosomething(接秘书 jms)方法时,该委托使用哪个接秘书方法即可,如下.

void 经理电话()
{
   接电话 jdh=null;//委托
   if(按键==1)
   {
        jdh=new 接电话(接秘书1);//接秘书1方法作为参数绑定到jdh委托上
   }
   if(按键==2)
   {
        jdh=new 接电话(接秘书2);
    }
   接电话(jdh);//调用委托
}

以上我们关心的重点是接通电话,而并不关心接通电话到谁,接通到谁是业务具体,在面向对象设计中,应该尽量从具体业务中抽离出一些与业务无关的通用模型,增加代码重用性,同时也使得这个代码精简.

我们再看一下在开发中,应该很少这么用.实际的开发中对委托用的做多的是事件,事件是以委托为基础衍生出来的,在.net中,界面上控件的事件都是通过委托来实现的,可以说委托无处不在,这也是我们为什么引入委托的原因,.net有自己系统自带的事件,而我们也可以自定义事件来为我们的业务服务,比如订阅模式中对委托事件的应用.

开发中哪些地方我们能用到委托呢?就个人而言,有如下一些应用吧,知识浅薄,欢迎补充.

首先,是.net在委托上的一些应用,这些可以让我们表层上写出更好看的代码,从2.0的匿名委托到3.0的lambda表达式,让我们的代码看起来更加直观,行云流水般漂亮.下面通过几个例子来看看同样功能函数的版本升级.

public delegate int GetMul(int x,int y);

int VisMul(int a,int b)
{
    return a*b; 
}

void Main()
{
      GetMul gm=new GetMul(VisMul);
      var data=gm(5,3);
      Console.WriteLine(data.tostring());
}

上面的代码实现输出两个整数的乘积.先声明一个GetMul委托;之后写一个函数,返回两个整数的乘积;主函数初始化委托,然后传递给委托两个整数5,3,输出为15.

这种是最直接对委托进行实用的方式,在2.0版本中,引入了匿名函数,我们可以看看如下代码,看看哪些地方得到了简化.

public delegate int GetMul(int x,int y);

void Main()
{
      GetMul gm=delegate(int x,int y)
                         {
                               return x*y;
                         };
       Console.WriteLine(gm(5,3).tostring());
}

如上即为匿名方式的实现,看看代码比之前的精简了什么,精简的主要是具体函数定义部分,自然这种方式并不适用于那些经常被其他方法调用的函数.在使用过程中,对于那些有可能不怎么使用,或者只是在此方法中使用一次的函数,我们可以直接通过匿名函数来实现,至少能简化代码,下面我们再看看3.0中的lambda表达式,如下代码.

void Main()
{
     Func<int, int, int> s = (x, y) => x * y;
     Console.WriteLine(s(5,3).tostring());
}

以上的写法表层代码更为简洁,甚至不用定义委托了.Func是3.5版中的一种委托简写方式,可以理解为微软对委托的一种封装,和Action类似,Action指定那些只有输入参数,没有返回值的委托;Func相反是有返回值,所以我们在写代码中,碰到委托可以想象是否可以用到这两种委托的简写方式.下面给一个Action的使用方法简例.

void Main()
{
      List<int> ids = new List<int>() { 1, 2, 3 };
      StringBuilder resultMsg = new StringBuilder();
      ids.ForEach(new Action<int>((int id) =>
      {
           resultMsg.AppendLine(id.ToString());
      }));
      Console.WriteLine(resultMsg.ToString());  
}

Action<int>表示一个输入为int的委托,而上面的例子用到了lambda表达式,(int id)=>{}实际上与 delegate(int id){}等价,这个熟练了自然会信手拈来.

就开发中那些地方用到委托这个命题,以上的这段内容只是在代码技巧上对委托进行了封装或者说表层上的简化,让编码者更加自然的编码,实际上我觉得微软总体上来说想把代码也变得如同汉字般象形,写起来更加合乎自然法则,面向自然.呵呵!

除了这些应用以外,自然在实际的运用中,我们通过委托带来方便,比如类间传递复杂的参数,List<T>集合等,我们可以通过委托来实现,实际上这个类之间传递参数和观察者模式有些关系(Observer),这里不详细介绍了.
最后来说说事件,如同属性对字段的封装一样,事件就是对委托的封装,他让委托更加安全,我们只通过+=和-=对事件进行注册和注销,而无法对事件进行直接=.我们来看看微软在.net中自带的委托事件.

public delegate void EventHandler(object sender, EventArgs e);

当我们生成一个按钮事件时,系统自动会生成下面代码:

this.button1.Click += new System.EventHandler(this.button1_Click);

意思就是,button1按钮的Click事件触发时,执行button1_Click这个函数方法,在EventHandler(object sender, EventArgs e)这个委托中,object代表触发主体,EventArgs代码其主体相关参数信息,咋们再看看其Click事件定义.

public event EventHandler Click;

即是对EventHandler委托的一个封装,整个事件过程既是Click触发绑定在其上的委托方法button1_Click.其实可以想一样,微软这个事件机制本身就实现了一种设计模式,至于.net内部是如何知晓这个事件,并为其生成事件代码,太深奥.实际上用代码来实现的一些设计模式,在微软设计自己的VS时,已经用过了.

暂时了解的就这么多,就到这了,第一次写技术博客,望大家指教!


 



 





 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值