委托
一、委托的本质
委托实际上就是指向函数的指针。在C#中委托是一种类型,定义一个委托就是定义一个新的类,它与类的地位是一样的,所以可以定义类的地方都可以定义委托!
实际上,使用delegate关键字定义的委托继承了System.MulticastDelegate类,而System.MulticastDelegate类又继承了System.Delegate。
Delegate:表示委托,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法。
MulticastDelegate:表示多路广播委托;即,其调用列表中可以拥有多个元素的委托。
个人理解:可以把委托理解成当一个函数无法直接调用的时候,将这个函数声明一个委托类型,也就是指向函数的一个指针,简单来说就是理解成给这个函数另外起一个名字,然后让它可以直接在外部进行调用,个人经常使用场景为不同界面之间如果产生相互之间函数调用的时候这个时候委托是一个非常好的选择!这样既能够保证窗口层次的传递性,也不会有冗余对象出现,也同时避免为传递数据大量使用静态变量。
二、使用委托的示例
delegate string DelegateMethod(int a, int b);//定义委托
class Program
{
static void Main(string[] args)
{
DelegateMethod dm = new DelegateMethod(Method);//或:DelegateMethod dm = Method
Console.WriteLine(dm(10, 20));//执行委托
Console.Read();
}
private static string Method(int a, int b)
{
return "相加结果:" + (a + b);
}
}
三、委托的Invoke与BeginInvoke方法
1、Invoke方法
实际上,给委托实例提供圆括号与调用委托的Invoke方法效果完全相同:
delegate string DelegateMethod(int a, int b);//定义委托
class Program
{
static void Main(string[] args)
{
DelegateMethod dm = Method;
Console.WriteLine(dm.Invoke(10, 20));//执行委托
Console.Read();
}
private static string Method(int a, int b)
{
return "相加结果:" + (a + b);
}
}
2、BeginInvoke方法
调用委托实例的BeginInvoke方法就是开启一个新的线程执行委托实例指向的方法。
delegate void DelegateMethod(int a, int b);//定义委托
class Program
{
static void Main(string[] args)
{
DelegateMethod dm = Method;
for (int i = 0; i < 10; i++)
{
dm.BeginInvoke(i, 20, null, null);//异步调用委托
}
Console.Read();
}
private static void Method(int a, int b)
{
Console.WriteLine("相加结果:" + (a + b));//执行委托
}
}
BeginInvoke方法有三种参数,第一种参数是委托实例指向的方法的参数(可能有多个);第二种参数的类型是AsyncCallback,AsyncCallback是一个委托类型,其定义是delegate void AsyncCallback(IAsyncResult ar),当调用BeginInvoke方法的委托实例异步执行完成时,就会执行该参数指向的方法;第三种参数是object类型,主要是向第二种参数传递一些值,一般可以传递被调用方法的委托,这个值可以使用IAsyncResult.AsyncState属性获得。
delegate void DelegateMethod(int a, int b);//定义委托
class Program
{
static void Main(string[] args)
{
DelegateMethod dm = Method;
dm.BeginInvoke(10, 20, MethodCompleted, null);//异步调用委托
Console.Read();
}
//异步委托
private static void Method(int a, int b)
{
Console.WriteLine("相加结果:" + (a + b));
Thread.Sleep(3000);
}
//回调函数
private static void MethodCompleted(IAsyncResult ar)
{
Console.WriteLine("休眠结束!");
}
}
3、委托的EndInvoke方法
如果调用了委托实例的BeginInvoke方法,就可以通过EndInvoke方法获得委托实例指向的方法的返回值,或是确定指向的方法已经被成功调用。
delegate string DelegateMethod(int a, int b);//定义委托
class Program
{
static void Main(string[] args)
{
DelegateMethod dm = Method;
IAsyncResult ar = dm.BeginInvoke(10, 20, null, null);//异步调用委托
string result = dm.EndInvoke(ar);//等待委托异步调用结束
Console.WriteLine(result);//输出返回值
Console.Read();
}
//异步委托
private static string Method(int a, int b)
{
Thread.Sleep(3000);
return "相加结果:" + (a + b);
}
}
四、Action、Func与Predicate(泛型委托)
除了为每个参数和返回类型定义一个新委托之外,还可以使用Action与Func泛型委托。使用泛型委托主要的优势是可以省略委托的定义。
1、Action无返回值的泛型委托
泛型Action委托表示引用一个void返回类型的方法,这个委托类可以有多个(≥0)参数且参数的类型可以不同(最多可以有16种不同类型的参数)。
class Program
{
static void Main(string[] args)
{
Action<int,int> dm = Method;//委托实例
dm(10,20);//调用委托
Console.Read();
}
private static void Method(int a, int b)
{
Console.WriteLine("相加结果:" + (a + b));
}
}
2、Func带有返回值的泛型委托
泛型Func委托与Action委托类似,不同点是Func允许调用带返回值类型的方法,而且其返回值类型的指定是Func<T1,T2,T3…Tn>中的最后一个类型(Tn),即Tn就是其返回值,其它类型都表示参数的类型。(最多可以有16种参数类型和一个返回值类型)
class Program
{
static void Main(string[] args)
{
Func<int, int, string> dm = Method;//委托实例
string result = dm(10, 20);//调用委托
Console.WriteLine(result);//输出返回值
Console.Read();
}
private static string Method(int a, int b)
{
return "相加结果:" + (a + b);
}
}
3、Predicate委托(常用于集合参数)
Predicate泛型委托,只能接受一个传入参数,返回值为bool类型。
class Program
{
static void Main(string[] args)
{
Predicate<int> dm = Method;//委托实例
if (dm(12))//调用委托
{
Console.WriteLine("偶数");
}
else
{
Console.WriteLine("奇数");
}
Console.Read();
}
private static bool Method(int a)
{
if(a%2==0)
{
return true;
}
return false;
}
}
五、多播委托
前面的委托只包含一个方法,但是委托也可以包含多个方法,这种委托称为多播委托。如果调用多播委托就可以按顺序连续调用多个方法,为此委托的定义就必须返回void,否则就只能得到委托调用的最后一个方法的结果。多播委托可以识别“+、-、+=、-=”运算符。
class Program
{
static void Main(string[] args)
{
Action<int> dm = null; //委托实例
for (int i = 0; i < 20; i++)
{
if (i % 2 == 0)
{
dm += Method1;
}
else
{
dm += Method2;
}
}
dm(123456);//调用多播委托
Console.Read();
}
private static void Method1(int a)
{
Console.WriteLine("委托1:" + a);
}
private static void Method2(int a)
{
Console.WriteLine("委托2:" + a);
}
}
六、使用委托定义匿名方法
class Program
{
static void Main(string[] args)
{
Action<int> dm = delegate(int a)
{
Console.WriteLine(a.ToString());
};//匿名方法
dm(123456);//调用委托指向的匿名方法
Console.Read();
}
}