C# 面试手册
进阶使用

委托与事件

委托是什么?

委托是寻址的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项久更无从知晓了。

而.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含对多个方法的引用。

C#中的委托是什麽?事件是不是一种委托?

  • 委托的本质是一个类,委托是将一种方法作为参数代入到另一种方法。
  • 事件是委托的实例,事件是一种特殊的委托。

在.NET中的委托是什么?

委托是寻址的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。我们无法判断这个指针实际指向什么,像参数和返回类型等项久更无从知晓了。而.NET委托完全不同,委托是类型安全的类,它定义了返回类型和参数的类型。委托类不仅包含对方法的引用,也可以包含对多个方法的引用。

在.NET中可以自定义委托吗?

声明一个委托类型,它的实例引用一个方法,该方法获取一个int参数,返回void。

public delegate void Feedback(int num);

理解委托的一个要点是它们的安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。 理解委托的一种比较好的方式是把委托当作这样一件事情:它给方法的签名和返回类型指定名称。其语法类似于方法的定义,需要在定义方法的前面加上delegate关键字。定义委托基本上就是定义一个新的类,所以可以在任何地方定义类的相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是public/private/protected等。

如何自定义委托?

声明一个委托类型,它的实例引用一个方法,该方法获取一个int参数,返回void。

public delegate void Feedback(int num);

理解委托的一个要点是它们的安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

理解委托的一种比较好的方式是把委托当作这样一件事情:它给方法的签名和返回类型指定名称。其语法类似于方法的定义,需要在定义方法的前面加上delegate关键字。

定义委托基本上就是定义一个新的类,所以可以在任何地方定义类的相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在名称控件中把委托定义为定义为顶层对象。访问修饰符可以是public/private/protected等。

.NET默认的委托类型有哪几种?

  1. Action <T> 泛型Action委托表示引用一个void返回类型的方法。这个委托类存在16种重载方法。 例如Action<in T1,In T2>调用没有参数的方法
  2. Func<T> Func调用带返回类型的方法。有16种重载方法。 例如Func委托类型可以调用带返回类型且无参数的方法,Func<in T,out TResult>委托类型调用带有4个参数和一个返回类型的方法。

简述Func与Action的区别?

Func是有返回值的委托,Action是没有返回值的委托。

什么是泛型委托?

Action就是泛型委托。

注意事项:

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

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

    delegate void Test(ref int i)
  3. 如果委托要通过C#的params关键字获取可变数量的额参数,要为委托的任何桉树指定默认值,或者要对委托的泛型类型参数进行约束,也必须定义自己的委托类型

    delegate void EventHandler(Object sender, TEventArgs e)
    where TEventArgs : EventArgs;
  4. 使用获取泛型实参和返回值的委托时,可利用逆变与协变。逆变:父类转换为子类;协变:子类转换为父类

什么是匿名方法?

匿名方法是用作委托的参数的一段代码。

//匿名方法,例1
Func<int, int> anon = delegate(int i)
{
    i = i+1;
    return i;
};
//输出2
Console.WriteLine(anon(1));
//匿名方法,例2
Action<int> anon2 = delegate(int i)
{
	i = i + 1;
};
//输出2
Console.WriteLine(anon(1));	

什么是闭包?

闭包就是能够读取其他函数内部变量的函数。C#通过Lambda表达式可以访问Lambda表达式块外部的变量,这成为c#闭包。当引用外部变量时,需要注意,外部变量变化时,lambda表达式的结果也可能会随着外部变量变化而变化。如下面的例子:

int y = 5;
Func<int, int> lambda = x => x + y;
Console.WriteLine(lambda(1));
y = 10;
Console.WriteLine(lambda(1));