首页 > 代码库 > C#学习(10):委托
C#学习(10):委托
1。疑问:
1.委托是什么?
2.为什么需要委托?
3.委托能用来做什么?
4.如何自定义委托?
5..NET默认的委托类型有哪几种?
6.怎样使用委托?
7.多播委托是什么?
8什么是泛型委托?
9.什么是匿名方法?
10.委托是否可以回调实例方法?
11.Lambda表达式是什么?
12.Lambda表达式怎么传参?
13.Lambda多行代码怎么写?
14.什么是闭包?
2。解答:
1.委托是什么?
本题主要考察委托的概念:委托是寻址的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项久更无从知晓了。而.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含对多个方法的引用。
2.为什么需要委托?
本题主要考察直接调用一个方法和通过委托来间接调用委托的区别。
在很多场景下直接调用方法是比较简单方便的,但是在某些场景下,使用委托来调用方法能达到减少代码量,实现某种功能的用途,比如说事件。
3.委托能用来做什么?
本题主要考察委托在我们写code时的用途。一个笼统的准则:当要把方法传给其他方法时,需要使用委托。比如下面几个场景:
a.启动线程和任务
调用System.Threading.Thread的一个实例上使用方法Start(),必须为计算机提供开始启动的方法的袭击,
即Thread类的构造函数必须带有一个参数,该参数定义线程调用的方法。
Thread t = new Thread(new ThreadStart(Go));//public static GO(){}
b.设计模式中的简单工厂模式。
向一个方法中传递一个子类的方法。
c.事件。
一般通知代码发生了什么事件。GUI编程主要处理事件。在引发事件时,运行库需要知道应执行哪个方法。
这就需要处理事件的方法作为一个参数传递给委托。
4.如何自定义委托
声明一个委托类型,它的实例引用一个方法,该方法获取一个int参数,返回void。
public delegate void Feedback(int num);
理解委托的一个要点是它们的安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。
理解委托的一种比较好的方式是把委托当作这样一件事情:它给方法的签名和返回类型指定名称。
其语法类似于方法的定义,需要在定义方法的前面加上delegate关键字。定义委托基本上就是定义一个新的类,
所以可以在任何地方定义类的相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,
还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是public/private/protected等
5..NET默认的委托类型有哪几种?
1.Action<T>
泛型Action<T>委托表示引用一个void返回类型的方法。这个委托类存在16种重载方法。
例如Action<in T1,In T2>调用没有参数的方法
2.Func<T>
Func<T>调用带返回类型的方法。有16种重载方法。
例如Func<out TResult>委托类型可以调用带返回类型且无参数的方法,
Func<in T,out TResult>委托类型调用带有4个参数和一个返回类型的方法。
3.等等
6.怎样使用委托
下面我将会用个例子来讲述怎样使用委托
1 // 声明一个委托类型,它的实例引用一个方法,该方法获取一个int参数,返回string 2 public delegate String myMethodDelegate(int myInt); 3 // 定义一些方法给委托变量引用 4 public class mySampleClass 5 { 6 // 定义一个实例方法 7 public String myStringMethod(int myInt) 8 { 9 if (myInt > 0)10 return ("positive");11 if (myInt < 0)12 return ("negative");13 return ("zero");14 }15 // 定义一个静态方法16 public static String mySignMethod(int myInt)17 {18 if (myInt > 0)19 return ("+");20 if (myInt < 0)21 return ("-");22 return ("");23 }24 }25 public static void Main()26 {27 // 给每个方法都创建一个委托实例28 // 对于实例方法,mySC必须提供29 // 对于静态方法,只需要指定类的名字30 mySampleClass mySC = new mySampleClass();31 myMethodDelegate myD1 = new myMethodDelegate(mySC.myStringMethod);32 myMethodDelegate myD2 = new myMethodDelegate(mySampleClass.mySignMethod);33 // 调用委托34 Console.WriteLine("{0} is {1}; use the sign \"{2}\".", 5, myD1(5), myD2(5));35 Console.WriteLine("{0} is {1}; use the sign \"{2}\".", -3, myD1(-3), myD2(-3));36 Console.WriteLine("{0} is {1}; use the sign \"{2}\".", 0, myD1(0), myD2(0));37 }
输出
5 is positive; use the sign "+".
-3 is negative; use the sign "-".
0 is zero; use the sign "".
7.多播委托是什么?
包含多个方法的委托叫做多播委托。如果调用多播委托,就可以顺序连续调用多个方法。
为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。
例子:
1 /// <summary> 2 /// 定义委托类型 3 /// </summary> 4 /// <param name="num"></param> 5 /// <returns>void</returns> 6 public delegate void Feedback(int num); 7 8 /// <summary> 9 /// 实例方法10 /// </summary>11 /// <param name="b"></param>12 /// <returns>void</returns>13 public void InstanceMethod(int a)14 {15 Console.WriteLine(a.ToString());16 }17 /// <summary>18 /// 静态方法19 /// </summary>20 /// <param name="a"></param>21 /// <returns>返回void</returns>22 public static void StaticMethod( int b)23 {24 Console.WriteLine((b * b).ToString());25 }26 27 //定义一个Program实例28 Program p = new Program();29 //委托feedback1指定回调方法:p.InstanceMethod30 Feedback feedback1 = new Feedback(p.InstanceMethod);31 //委托feedback2指定回调方法:StaticMethod32 Feedback feedback2 = new Feedback(StaticMethod);33 //输出234 feedback1(2);35 //输出436 feedback2(2);37 38 //----多播委托-------39 Feedback fbChain = null;40 //将feedback1添加到fbChain委托中41 fbChain += feedback1;42 //将feedback2添加到fbChain委托中43 fbChain += feedback2;44 //输出:45 //246 //447 fbChain(2);
8.什么是泛型委托?
比如第5题提到的,Action<T>就是泛型委托。
注意事项:
1.建议尽量使用这些委托类型,而不是在代码中定义更多的委托类型。这样可以减少系统中的类型数目,同时简化编码
2.如果需要使用ref或out关键字,以传引用的方式传递一个参数,就可能不得不定义自己的委托:
delegate void Test(ref int i)
3.如果委托要通过C#的params关键字获取可变数量的额参数,要为委托的任何桉树指定默认值,
或者要对委托的泛型类型参数进行约束,也必须定义自己的委托类型
delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e) where TEventArgs : EventArgs;
4.使用获取泛型实参和返回值的委托时,可利用逆变与协变。逆变:父类转换为子类;协变:子类转换为父类
9.什么事匿名方法
匿名方法是用作委托的参数的一段代码。
1 //匿名方法,例1 2 Func<int, int> anon = delegate(int i) 3 { 4 i = i+1; 5 return i; 6 }; 7 //输出2 8 Console.WriteLine(anon(1)); 9 10 //匿名方法,例211 Action<int> anon2 = delegate(int i)12 {13 i = i + 1;14 };15 //输出216 Console.WriteLine(anon(1));
10.委托是否可以回调实例方法
可以。委托可以回调实例方法和静态方法。如果是实例方法,委托需要知道方法操作的是哪个对象实例。
11.Lambda表达式是什么?
从C#3.0开始,就可以使用一种新语法把实现代码赋予委托:Lambda表达式。
只要有委托参数类型的地方,就可以使用Lambda表达式。
12.Lambda表达式怎么传参?
Lambda表达式有几种定义参数的方式。
1.只有一个参数,只写出参数名就足够了。
如下面的例子:
定义了一个泛型委托,输入参数是一个string类型,返回一个string类型,
lambda表达式:s=>s.Replace(‘a,b‘)
委托引用的方法名:oneParam
传入参数:abc
打印结果:bbc
1 Func<string, string> oneParam = s => s.Replace(‘a‘, ‘b‘);2 Console.WriteLine(oneParam("abc"));3 Console.ReadKey();
2.如果委托使用多个参数,就把参数名放在小括号中。
如下面的例子:
定义了一个泛型委托,输入参数是两个int类型(可以给小括号中的变量名添加参数类型),返回一个int类型,
lambda表达式:(i, j) => i*j
委托引用的方法名:twoParam
传入参数:2和4
打印结果:8
1 Func<int, int, int> twoParam = (i, j) => i*j;2 Console.WriteLine(twoParam(2,4));
13.Lambda多行代码怎么写?
添加大括号,如果需要返回值,则必须添加return语句
2 { 3 i = i + 1;4 i = i * j;5 return i;6 };7 Console.WriteLine(test(2, 4));
打印结果:12
14.什么是闭包?
通过Lambda表达式可以访问Lambda表达式块外部的变量,这成为闭包。
当引用外部变量时,需要注意,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化而变化。
如下面的例子:
1 int y = 5;2 Func<int, int> lambda = x => x + y;3 Console.WriteLine(lambda(1));4 y = 10;5 Console.WriteLine(lambda(1));
第一次打印出6,第二次打印出11
C#学习(10):委托