委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。委托类型有:delegate、Action、Func、Predicate。事件是一种特殊的委托。
1、委托的声明
1.1、Delegate 是常用到的一种声明。
至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。例如,表示有两个参数,并返回int型。
/// <summary>/// 两数相乘的委托/// </summary>public delegate ResultT MultiplyDelegate<T1,T2,ResultT>(T1 x, T2 y);class Program { private static MultiplyDelegate<int, int, int> multiplyDelegate; static void Main(string[] args) { multiplyDelegate += Multiply;//或者:multiplyDelegate=new MultiplyDelegate<int, int, int>(Multiply); Console.WriteLine(multiplyDelegate(10, 20)); } private static int Multiply(int x,int y) { return x * y; } }
1.2、Action 无返回值的泛型委托。
Action 表示无参,无返回值的委托
Action<int,string> 表示有传入参数int,string无返回值的委托
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托
Action至少0个参数,至多16个参数,无返回值。
static void Main(string[] args) { InvokeAction( new Action<string>(ShowString),"字符串Action委托"); InvokeAction(new Action<Double>(ShowDouble), 9.09); InvokeAction<string>(p=> { Console.WriteLine(p); }, "Lambda表达式委托"); }private static void InvokeAction<T>(Action<T> action,T t) { action.Invoke(t); }private static void ShowString(string s) { Console.WriteLine(s); }private static void ShowDouble(double d) { Console.WriteLine(d); }
1.3、Func 有返回值的泛型委托
Func<int> 表示无参,返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可是void。
class Program { static void Main(string[] args) { Func<int, int, int> func = new Func<int, int, int>(Multiply); Console.WriteLine(func(10, 20)); } private static int Multiply(int x,int y) { return x * y; } }
可以使用 Action<T1, T2, T3, T4> 委托以参数形式传递方法,而不用显式声明自定义的委托。 封装的方法必须与此委托定义的方法签名相对应。 也就是说,封装的方法必须具有四个均通过值传递给它的参数,并且不能返回值。(在 C# 中,该方法必须返回 void)通常,这种方法用于执行某个操作。
1.4、Predicate 返回bool型的泛型委托
Predicate<int> 表示传入参数为int 返回bool的委托。Predicate有且只有一个参数,返回值固定为bool。该委托表示定义一组条件并确定指定对象是否符合这些条件的方法。此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素。
static void Main(string[] args) { Tuple<int, int> tuple1 = new Tuple<int, int>(89, 34); Tuple<int, int> tuple2 = new Tuple<int, int>(12, 34); Tuple<int, int> tuple3 = new Tuple<int, int>(125, 30); Tuple<int, int> tuple4= new Tuple<int, int>(192, 340); Tuple<int, int>[] tuples = new Tuple<int, int>[] { tuple1, tuple2, tuple3, tuple4 }; Tuple<int, int> frist = Array.Find(tuples, Product); Console.WriteLine(frist.ToString()); }private static bool Product(Tuple<int ,int> tuple) { return tuple.Item1> tuple.Item2; }
使用带有 Array.Find 方法的 Predicate 委托搜索 Tuple<int ,int> 的数组。如果 Item1大于Item2,此委托表示的方法 Product将返回 true。Find 方法为数组的每个元素调用此委托,在符合测试条件的第一个点处停止。
2、多播委托
前面使用到的委托都只包含了一个方法的调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,需要多次显示调用该方法---多播委托。多播委托的签名必须返回void,否则只能获取到最后一个方法的结果。多播委托使用前面的“multiplyDelegate += Multiply”形式实现添加多个委托方法。如果正在使用多播委托,对同一委托调用方法链的顺序并未正式定义,因此应该避免编写依赖于以特定顺序调用方法的代码。
多播委托可能出现调用方法停止问题。如果委托方法中的某一个方法抛出异常,整个迭代就会停止,未执行的方法便不会执行。定义两个方法One()与Two(),其中One()方法中会抛出一个异常
private static void One() { Console.WriteLine("One"); throw new Exception("One"); }private static void Two() { Console.WriteLine("Two"); }
在Main()方法中创建一个委托d,引用One和Two方法。调用委托d,并使用try……catch捕获异常:
static void Main(string[] args) { Action d = One; d += Two; try { d(); } catch(Exception e) { Console.WriteLine(e.Message); } }
解决多播委托的异常导致整个迭代方法停止问题,便需要有自己的迭代方法。使用Delegate类定义GetInvocationList()方法获取添加到委托的Delegate对象数组,使用循环迭代、捕获异常即可:
static void Main(string[] args) { Action d = One; d += Two; Delegate[] delegates = d.GetInvocationList(); foreach (Action item in delegates) { try { item(); } catch (Exception e) { Console.WriteLine(e.Message); } } }
3、委托的清空
委托的添加可以像前面使用“+”符号添加,同样的可以使用“-”符号来减少委托。也可以对委托重新赋值为null,清空所有委托。
4、委托的优点
委托类似于 C++ 函数指针,但它们是类型安全的
委托允许将方法作为参数进行传递
委托可用于定义回调方法
委托可以链接在一起;例如,可以对一个事件调用多个方法
方法不必与委托签名完全匹配
共同学习,写下你的评论
评论加载中...
作者其他优质文章