您的位置:首页 > 其它

关于委托的研究

2015-11-26 15:04 330 查看
最近有朋友因为委托的问题一直受困扰,这里总结一下

什么是委托?

  委托顾名思义,就是自己不干,让别人干,这个有别与C和C++ 的函数指针(还是学过C和C++的),这里是一种方法,而且不管是静态方法还是非静态方法,而函数指针只是指向静态函数,这点也是两者的主要区别。一般委托会用在观察者模式(Observer)里。

为什么要用?什么时候用委托?或者说使用委托的好处是什么呢?

   说白了委托就是第三方,调用者告诉第三方要做什么,然后调用者就不用管了,这个委托(第三方)就会去调用方法去帮你实现。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。

好处:

1、相当于用方法作为另一方法参数(类似于C的函数指针)
2、在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托
3、当不知道方法具体实现什么时使用委托,如:事件中使用委托

那么如何使用委托呢?这里总结了一下,主要分三步走;

一、定义一个委托delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。 

二、创建delegate对象,并将你想要的传递函数作为参数传入。

创建代理对象的方法:(区别是在于方法是否静态)

1、MyDelegate myDeleGate=new MyDelegate(实例名.方法名)

2、MyDelegate myDeleGate=new
MyDelegate(类名.方法名)

三、调用,上面定义的对象调用方法。

如何使用委托呢?也是有三种方式;

一、Labmda表达式

List<int > list = new List<int> ();//定义一个list数组
list.Add (121);//添加数据
list .Add (234);
list .Add (123);
list .Add (123);
list .Add (123);
foreach (var i in list) {//遍历打印
Console.Write(i+" ");
}
Console.WriteLine ();
list .RemoveAll ((int x) => {//定义委托指向删除方法<pre name="code" class="csharp">  if (x == 123 || x == 234) {
return true;
}
return false;
});
foreach (var i in list) {//遍历打印删除方法执行后的数组
Console.Write(i+" ");
}<span style="font-family: Arial, Helvetica, sans-serif;">         </span>



二、匿名委托(通俗讲是直接加方法体)

list.RemoveAll (delegate (int x)
{
if (x == 123||x==234) {
return true;<pre name="code" class="csharp">                            }
return false;
});
foreach (var i in list) {
Console.Write(i+" ");
}<span style="font-family: Arial, Helvetica, sans-serif;">      </span>


三、就是比较常见的也是使用最多的

using System.Collections;
using System.Collections.Generic;

namespace lesson13
{
  delegate void myDelegate(double money);//1、定义一个参数的委托
    class Host{//定义Host的类
        public  void sell(double money)
             {
                  Console.WriteLine (money+"sell");
                       }
    }

    class MainClass
    {
        public static void Main (string[] args)
        {
                     
            Host h = new Host ();//实例化
            myDelegate my = h.sell;//2、定义委托对象指向方法         
            my(14.5);3、调用  也可以使用 my.Invoke(14.5);
}
显然运行结果就是14.5sell。调用委托对象的Invoke()方法,Invoke后面的括号中应包含调用该委托中的方法时使用的参数。实际上,给委托实例提供括号与调用委托类的Invoke()方法完全相同。因为Invoke()方法是委托的同步调用方法。

如何指向多个方法呢?

因为委托就是委托与相同类型方法,比如游戏里的回血回蓝啊,这样的就需要委托多个方法。

一个委托可以通过+运算委托关联多个方法,叫多路广播委托(对应于单路广播委托)。

namespace ConsoleApplication1
{
delegate void myDelegate(double money);
class Host{
public  void rent(double money)
{
Console.WriteLine (money+"rent");
}
public  void sell(double money)
{
Console.WriteLine (money+"sell");
}
}

class MainClass
{
public static void Main (string[] args)
{

Host h = new Host ();
myDelegate my = h.sell;
my += h.rent;
my (12.2);
显然结果就是12.2sell

                       12.2rent

            要是删除这个委托方法,

my -= h.rent;
显然结果就是12.2sell了。

如果方法有返回值呢?情况是不一样的。

namespace ConsoleApplication1
{
delegate int SumDelegate(int x,int y);//1、定义两个参数的委托
class Host{
public int sum(int a,int b)
{
return a + b;
}
public int sum1(int a,int b)
{
return a + b+5;
}
}
class MainClass
{
public static void Main (string[] args)
{

Host h = new Host ();//实例化
SumDelegate sum = h.sum;
sum += h.sum1;
Console.WriteLine (sum(2,3));//带返回值的委托返回最后一个
}}
结果带返回值的类型在使用多路广播的时候只是打印了10=2+3+5,也就是说只是委托了最后一个。

上面的委托定义在类外面,委托写类里这种情况跟上面的情况一样么?是有区别的

委托写在类里,就是私有的;外面拿不到。要想用就用event

class Fun{
//委托写在类里,就是私有的;外面拿不到。要想用就用event
public   delegate void Greet(string str);
public  event Greet greet;
public void s(string name) {
greet (name);
}
}<pre name="code" class="csharp">  public static void Main (string[] args)
{

Fun fun= new Fun ();
fun.greet += delegate (string name) {
Console.WriteLine ("爱" + name);
};
fun.s("老七");}//<pre name="code" class="csharp">结果:爱老七;给委托添加了一个打印的方法,传个值“老七”,同时也是实现了方法,就打印了。



这里可以看出用法其实只是加个Event其他用法还是可以一样使用的。可是我们使用的是greet不是Greet.

上面还定义一个方法  :

public void s1(string name)
{
Console.WriteLine(name + "老七");
}<pre name="code" class="csharp">public static void Main (string[] args)
{
Fun fun= new Fun ();
fun.greet += fun.s1;
fun.s1("爱");}



输出一样的结果。

这里必须使用+=运算符。

这里还有一个问题,我们把Event删了还是可以执行的,为什么呢?不是说写在类了必须要用Event么?

这里是以设计模式——观察者模式来说;

     event是对委托对象的一个封装,不用event直接就可以用了,相当于一个公有的变量直接在类外面用了.破坏了封装,如果使用event,直接不能用,只能调用方法来用,这样就没有破坏封装了.

      event 事件都可以用delegate来完成。event强调了事件,通过订阅事件来获得通知。

      事件是针对某一个具体的对象的,一般在该对象的所属类A中写好事件,并且写好触发事件的方法,那么这个类A就是事件的发布者,然后在别的类B里面定义A的对象,并去初始化该对象的事件,让事件指向B类中的某一个具体的方法,B类就是A类事件的订阅者。当通过A类的对象来触发A类的事件的时候(只能A类的对象来触发A类的事件,别的类的对象不能触发A类的事件,只能订阅A类的事件,即实例化A类的事件),作为订阅者的B类会接收A类触发的事件,从而使得订阅函数被执行。一个发布者可以有多个订阅者,当发布者发送事件的时候,所有的订阅者都将接收到事件,从而执行订阅函数,但是即使是有多个订阅者也是单线程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: