C#委托基础

  委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。委托类型有: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++ 函数指针,但它们是类型安全的
  • 委托允许将方法作为参数进行传递
  • 委托可用于定义回调方法
  • 委托可以链接在一起;例如,可以对一个事件调用多个方法
  • 方法不必与委托签名完全匹配
posted @ 2018-06-26 21:13  一只独行的猿  阅读(192)  评论(0编辑  收藏  举报