zoukankan      html  css  js  c++  java
  • 不惧面试:委托

    原文地址:不惧面试:委托

    v博客前言

    先交代下背景,写这篇博客的原因是一些常用的知识点得温故而知新。第二个原因是之前看过一些书,写过一些代码,但是没有总结下来,下次再写code的时候,发现有点茫然,所以决定将此知识点总结下来,方便以后查看。第三个原因就是为了通过写博客,来保持长期学习的过程,每天打开博客园,发现上面发表博客的人,孜孜不倦地在学习,自己的心中当然有落差,为什么别人那么牛,所以我得抓紧时间学习,看书,总结。

    v写在前面

    如果您对以下的可能面试问到的题有所疑惑或不知道这些知识点,请继续往下看,如果对您有所帮助,请点个赞;如果您对这些可能问到的知识点都胸有成竹,也请指点一二。

    v正文开始

    面试常见题:

    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<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.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);

    8.什么是泛型委托?★★★

         比如第5题提到的,Action<T>就是泛型委托。

    注意事项:

      1.建议尽量使用这些委托类型,而不是在代码中定义更多的委托类型。这样可以减少系统中的类型数目,同时简化编码

      2.如果需要使用refout关键字,以传引用的方式传递一个参数,就可能不得不定义自己的委托:

        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

    传入参数:24

    打印结果: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

    v写在最后

    关于委托的知识点还有很多没有总结出来,比如说委托和反射,委托的底层实现等等。面试经常会问到也就是上面总结的。后续还会总结更多关于.NET的知识点。希望得到园友们的支持!


    作  者: Jackson0714
    出  处:http://www.cnblogs.com/jackson0714/
    关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

  • 相关阅读:
    Python Django 编写一个简易的后台管理工具2-创建项目
    leetcode-解题记录 771. 宝石与石头
    leetcode-解题记录 1108. IP 地址无效化
    Python Django 编写一个简易的后台管理工具1-安装环境
    备忘录
    Pollard_rho 因数分解
    ProgrammingContestChallengeBook
    HDU ACM-Steps
    ARCH-LINUX 折(安)腾(装)记
    各种Python小玩意收集
  • 原文地址:https://www.cnblogs.com/jackson0714/p/5111347.html
Copyright © 2011-2022 走看看