委托的存在是因为,我们有时候需要将一个函数作为另一个函数的参数,这时就要用的委托(Delegate)机制,,,
委托用关键字delegate声明,他实际上定义了一种“函数类型”,明确规定了函数参数类型和返回值类型。(即无参数无返回值的委托,只能接受无参数无返回值的方法,反之亦然,,)
声明委托:
在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字段和方法组成的,然后使用这个类实例化对象。在我们使用委托的时候,也需要经过这两个阶段,首先定义委托,告诉编译器我们这个委托可以指向哪些类型的方法,然后,创建该委托的实例
定义委托的语法如下:
delegate void MethodInvoker(int x);
定义了一个委托叫做MethodInvoker,这个委托可以指向什么类型的方法呢?
这个方法要带有一个int类型的参数,并且方法的返回值是void的。
定义一个委托要定义方法的参数和返回值,使用关键字delegate定义。
定义委托的其他案例:
delegate double TwoLongOp(long first,long second);
delegate string GetAString();
.NET编译器严格检查函数类型和未做的类型是否匹配,只有完全匹配才能进行转换转换之后的委托实例作为参数,传递给调用它的函数,
利用委托可以实现以函数为参数,提高程序的通用性,委托用关键字的delegate声明,实际上创建,一种委托相当于创建一个从System.Delegate派生出来的类,类中有一个调用列表,列表中包含着委托函数的引用,与c++的函数指针相比委托是一个在类型安全的方式。
小例:
using System;
namespace 委托
{
class Program
{
//定义委托 返回值string类型,无参数
private delegate string GetAString();
static void Main(string[] args)
{
//======================构造函数使用委托====================
int x = 410;
//使用委托声明实例 str指向了Tostring方法
GetAString str = new GetAString(x.ToString);
string res = str(); //委托类型调用方法
Console.WriteLine(res);
//======================直接赋值法使用委托====================
GetAString str1 = x.ToString;
string res1 = str1.Invoke(); //通过invoke方法调用str1所引用的方法
//string res1 = str1(); //是一样的,
Console.WriteLine(res);
//示例:使用委托作为参数
GetAString getastring = GetName;
Console.WriteLine(getastring());
getastring = GetAge;
Console.WriteLine(getastring());
Console.ReadKey();
}
static string GetName()
{
string str = "这是GetName方法";
return str;
}
static string GetAge()
{
string str = "这是GetAge方法";
return str;
}
}
}
系统预定义的委托:
除了我们自己定义的委托之外,系统还给我们提供过来一个内置的委托类型,Action和Func
Action委托引用了一个void返回类型的方法,T表示方法参数,先看Action委托有哪些
Action委托示例
namespace Action委托
{
class Program
{
static void Main(string[] args)
{
//系统内置的一个委托类型,它指向一个没有返回值,没有参数的方法
Action method1 = Show;
method1();
//利用泛型,定义没有返回值,带参数的委托
Action<string> method2 = Show;
method2("CZHENYA");
//系统会自动识别重载方法,,Action可以通过泛型来添加参数(最多支持16个参数),但是一定没有返回值
Console.ReadLine();
}
static void Show()
{
Console.WriteLine("Hello Czhenya");
}
static void Show(String name)
{
Console.WriteLine("HELLO"+name);
}
}
}
Func引用了一个带有一个返回值的方法,它可以传递0或者多到16个参数类型,和一个返回类型
//func委托实例
namespace Func委托
{
class Program
{
static void Main(string[] args)
{
//func 中的泛型是指定的方法的返回值类型,,
Func<int> method = Show1;
Console.WriteLine("方法的返回值是:"+ method());
//func 中的泛型是最后一个类型必须是函数的返回值类型,前面的是方法参数类型可以输入(0-16)
Func<int,string> method1 = Show2;
Console.WriteLine(method1(20));
Console.ReadKey();
}
static int Show1()
{
return 111;
}
static string Show2(int age)
{
Console.WriteLine(age);
return "Czhenya";
}
}
}
多播委托
多播委托:我们把包含多个函数的委托称为多播委托(Muiticast Delegate),所有被委托函数的引用都存储在多播委托类的调用列表中,当调用多播委托时,会按顺序依次调用列表中的所有函数。
向多播委托中注册函数的语法为:
通过+=运算符向多播委托中注册函数
从多播委托中删除函数的语法:使用-=运算符,,
注:多播委托只能得到调用的最后一个方法的结果,一般多播委托的返回值只能是void ,,,
namespace 多播委托
{
class Program
{
static void Main(string[] args)
{
//多播委托
Action method = Text1;
method += Text2;
//method();
//method -= Text1;
//当委托没有指向任意一个方法的时候,会报出异常,,,
//获得委托中的所有方法
Delegate[] delegates = method.GetInvocationList();
//遍历出来,挨个调用
foreach (Delegate item in delegates)
{
//item();
item.DynamicInvoke();
}
Console.ReadKey();
}
static void Text1()
{
Console.WriteLine("Text1");
}
static void Text2()
{
Console.WriteLine("Text2");
}
}
}