C#委托之如何理解委托⾯试常见题:
⾯试常见题:
1.委托是什么?★☆
2.为什么需要委托?★☆
3.委托能⽤来做什么?★☆
4.如何⾃定义委托★☆
5…NET默认的委托类型有哪⼏种?★☆
6.怎样使⽤委托?★★★
7.多播委托是什么?★★★
8什么是泛型委托?★★★
9.什么是匿名⽅法?★★
10.委托是否可以回调实例⽅法★★★
11.Lambda表达式是什么?★
12.Lambda表达式怎么传参?★★★
13.Lambda多⾏代码怎么写?★★
14.什么是闭包?★★
事件的⾯试题我放在下⼀篇⾥⾯。看完这些题⽬,⼼中是否有疑惑呢?那就接着看呗,我来帮您解答⼼中的疑惑o()o
参考答案:
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  泛型Action委托表⽰引⽤⼀个void返回类型的⽅法。这个委托类存在16种重载⽅法。  例如Action<in T1,In T2>调⽤没有参数的⽅法
2.Func  Func调⽤带返回类型的⽅法。有16种重载⽅法。  例如Func委托类型可以调⽤带返回类型且⽆参数的⽅法,  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 StringMethod);
32        myMethodDelegate myD2 = new SignMethod);
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.InstanceMethod
30        Feedback feedback1 = new Feedback(p.InstanceMethod);
31        //委托feedback2指定回调⽅法:StaticMethod
32        Feedback feedback2 = new Feedback(StaticMethod);
33        //输出2
34        feedback1(2);
35        //输出4
36        feedback2(2);
37
38        //----多播委托-------
39        Feedback fbChain = null;
40        //将feedback1添加到fbChain委托中
41        fbChain += feedback1;
42        //将feedback2添加到fbChain委托中
43        fbChain += feedback2;
44        //输出:
45        //2
46        //4
47        fbChain(2);writeline方法属于类
8.什么是泛型委托?★★★
⽐如第5题提到的,Action就是泛型委托。
注意事项:
  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        //匿名⽅法,例2
11        Action<int> anon2 = delegate(int i)
12        {
13            i = i + 1;
14        };
15        //输出2
16        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语句
1 Func<int, int, int> test = (i, j) =>
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
关于委托的知识点还有很多没有总结出来,⽐如说委托和反射,委托的底层实现等等。⾯试经常会问到也就是上⾯总结的。后续还会总结更多关
于.NET的知识点。
★★写在最后
委托(delegate)是⼀种存储函数引⽤的类型。这听起来相当深奥,但其机制是⾮常简单的。委托的声明⾮常类似于函数,但不带函数体,且要使⽤delegate 关键字。委托的声明制定了⼀个返回类型和⼀个参数列表。
定义了委托后,就可以声明该委托类型的变量。接着把这个变量初始化为与委托具有相同返回类型和参数列表的函数引⽤。之后,就可以使⽤委托变量调⽤这个函数,就像该变量是⼀个函数⼀样。
有了引⽤函数的变量后,就可以执⾏⽆法⽤其他⽅式完成的操作。例如,可以把委托变量作为参数传递给⼀个函数,这样,该函数就可以使⽤委托调⽤它引⽤的任何函数,⽽且在运⾏之前不必知道调⽤的是哪个函数。下⾯的⽰例使⽤委托访问两个函数中的⼀个。
(1)在C:\BegVCSharp\Chapter06⽬录中创建⼀个新的控制台应⽤程序Ch06Ex05.
(2)把下列代码添加到Program.cs中:
class  Program
{
delegate double ProcessDelegate(double param1, double param2);
static double Multiply(double param1,  double param2) =>param1 *param2;
static double Divide(double param1, double param2) =>param1/param2;
static void Main(string[] args)
{
ProcessDeletegate process;
WriteLine("Enter 2 numbers separated with a comma:");
string input  = Readline();
int commaPos = input.IndexOf(',');
double param1 = ToDouble(input.Substring(0,commaPos));
double param2 = ToDouble(input.Substring(commaPos + 1,input.Length - commaPos - 1));
WriteLine("Enter M to multiply or D to divide:");
input=ReadLine();
if(input=="M")
process = new ProcessDelegate(Multiply);
else
process = new ProcessDelegate(Divide);
WriteLine($"Result: {process(param1,param2)}");
ReadKey();
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。