C#-委托delegate
目录
委托
委托的定义
【定义】:委托是c#中函数回调机制,就是c语言中的函数指针在面向对象中的封装;简而言之就是函数指针。
它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。
委托和类相似,都是用户自定义的一种类型,只不过类表示的数据的集合,而委托表示的是一个或多个方法
【理解】:类比声明一个字符类型的变量“string name ”,其中string 是一个类,定义了name参数所能代表的值的种类,也就是name参数的类型。
【作用与意义】:
这种将方法动态地赋给参数的做法,可以避免在程序中大量使用if-else(switch)语句,同时使得程序具有更好的可扩展性。
委托的声明
【使用方法】:
关键字 delegate
委托和所引用的方法必须保持一致:
1、参数个数、类型、顺序必须完全一致。
2、返回值必须一致。
委托的实例
//声明一个委托指向一个函数,注意声明在同一个命名空间 public delegate void delsayhi(string name); class program { static void main(string[] args) { //------------------------------------------------------------------------------法1 //delsayhi del=new delsayhi (sayhichinese ); //☆注意函数名直接赋值给委托,不需要在函数名之后加括号 //sayhi("志铭", del); //委托就是为把一个函数当参数,但这样不明显 //------------------------------------------------------------------------------法2 //可以直接把一个函数给委托 //delsayhi del = sayhichinese; //☆注意函数名直接赋值给委托,不需要在函数名之后加括号 //sayhi("志铭", del); //------------------------------------------------------------------------------法3 //既然可以法2 ,那干脆直接如下,这样你就可以发现函数作为了参数 //sayhi ("志铭", sayhichinese); //------------------------------------------------------------------------------多播委托 //委托可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托, //这就是——多播委托 //当调用这个委托的时候,将依次调用其所绑定的方法。在这个例子中,语法如下 //delsayhi del=new delsayhi (sayhichinese ); //del += sayhienglish;//使用+=给此委托变量再绑定一个方法 //sayhi("志铭", del); //-------------------------------------------------------------------------------取消绑定 //既然给委托可以绑定一个方法, //那么也应该有办法取消对方法的绑定,很容易想到,这个语法是“-=”: //delsayhi del = new delsayhi(sayhichinese); //del += sayhienglish;//使用+=给此委托变量再绑定一个方法 //sayhi("志铭", del); //del -= sayhichinese;//使用-=给此委托变量取消绑定一个方法 //sayhi("志铭", del); //不使用sayhi函数,在新建了了委托对象后直接使用委托作函数 //注:当然我们知道可以在这里直接使用sayhichinese和sayhienglish俩个函数,我们在这里就是举例子 delsayhi del = new delsayhi(sayhichinese); if (null != del)//注意调用委托的时候一定要先判断委托是否为空,为空时会抛异常 { del("志铭");//其实是del.invoke("志铭")的简写 } console.readkey(); } //sayhi这个函数就是为了把下面两个函数sayhichinese和sayhienglish统一起来 //我想在这个函数中调用这两个函数,也就是有一个函数作为参数,但具体哪一个不确定 //所以我定义了一个委托delsayhi指向这两个函数 public static void sayhi(string name, delsayhi del) { del(name); } public static void sayhichinese(string name) { console.writeline("你好" + name); } public static void sayhienglish(string name) { console.writeline("hello" + name); } }
委托的注意细节
- 带有返回值的委托
如果委托有返回值并且在调用列表中有一个以上的方法(即多播委托),会发生下面的情况。
- 调用列表中最后一个方法返回的值就是委托调用返回的值。
- 调用列表中所有其他方法的返回值都会被忽略。
例如
delegate int mypel();//声明有返回值的方法 class myclass { int intvalue 5; public int add2(){ intvalue +=2;return intvalue;} public int add3(){ intvalue +=3;return intvalue;} } class program { static void main() { myclass mc=new myclass(); mydel mdel=mc.add2;//创建并初始化委托 mdel +=mc.add3//增加方法 mdel +=mc.add2//增加方法 console.writeline("value:{0}",mde1());调用委托并使用返回值 } }
结果:value:12;
泛型委托(详见《精通c#》--10.4泛型委托)
.net中内置类两个委托类型action<>和func<>,用法和自己定义的委托一样,只是不需要我们自己声明。
建议使用委托的时候就先考虑这两种委托
1.action<>委托
action<>类型的委托指向--最多16个参数并返回值为void的方法。
class program { static void main(string[] args) { action<string> del=sayhichinese;//定义一个action<string>委托,指向的方法返回值为void,有一个string类的参数。 //你想想,你之前使用委托是不是要要自己声明一个委托类型了 //这里就相当于.net已经帮我们 delegate void action<t>(t p) if (null != del) { del("志铭"); } console.readkey(); } public static void sayhichinese(string name) { console.writeline("你好" + name); } public static void sayhienglish(string name) { console.writeline("hello" + name); } }
3.func<>委托
func<>类型的委托指向--最多16个参数且有返回值的方法。
有一点要注意的就是,类型列表的顺序:func<>最后的一个类型参数是返回值的类型
show your code:
class program { static void main(string[] args) { func<int,int,string> del=sumtostring; //注意类型参数列表中的类型顺序,最后一个string 是函数返回值的类型 //这里就相当于.net已经给我们 delegate rt func<t1,t2,rt>(t1 x,t2 y) console.writeline(del(1,2)); } public static string sumtostring(int x,int y) { return (x+y).tostring(); } }
附录
-
在代码结构的设计上使用委托可以降低类与类之间的耦合性。
有两个类aclass和bclass,现在当某个条件得到满足的时候,aclass中的方法afunc调用bclass中的方法bfunc()。
代码如下:
public class program { aclass aobj = new aclass(); void main() { aobj.afunc(); } } public class aclass { bclass bobj=new bclass(); public void afunc() { //当某个条件满足时 if(true) { bobj.bfunc(); } } } public class bclass { public void bfunc() { } }
这样的写法使得a类和b类之间的关系为强耦合的关系,b的变化会在很大的几率上影响到a,我们将这样的关系称之为不稳定的关系,这是面向对象编程设计所不提倡的,那么如何将不稳定的关系变为稳定的关系呢?方法有多种,委托的应用就是其中一种。
代码如下:
//声明一个委托类型,它能接受的函数类型是没有返回也没有参数 public delegate void mydelegate(); public class aclass { //定义一个委托类型的变量 ,变量名字为 mydelagate public mydelegate mydelagate = null; public void afunc() { //当某个条件满足时 if(true) { if(mydelagate != null) { mydelagate(); } } } } public class bclass { public void bfunc() { } } public class pragrom { aclass aobj = new aclass(); bclass bobj = new bclass(); void main() { aobj.mydelagate = bobj.bfunc(); aobj.afunc(); } }
可以看到,只需要将b类中的方法通过公开的委托注册到a类去执行,这样就避免了a类和b类之间的相互引用,提高了类关系之间的稳定性。