(语法基础)委托学习总结(三)泛型委托

之前,我们学习总结了委托这个概念,也阐述了委托,匿名方法,lambda表达式三者之间的关系,那么今天再来继续学习委托更深层次的东西:泛型委托,什么是泛型,这个概念我也会在之后做出总结,这里不做很深层次的讨论,重点是讨论泛型和委托如何配合使用,其实泛型这个概念在这里也不会对我们对委托的理解有太大的影响,我们只要大概知道泛型就是一种动态的类型,它在使用时可以代表任意类型,下面我们再来回顾一下我们是如何定义普通委托的:

public delegate int 委托名(int a, int b);

这是委托的定义,它的定义有这几个特点,(1)可以用访问修饰符修饰。(2)delegate关键字。(3)有返回值和参数。

我们之前也说了,委托是一种类型,与之对应的方法必须和它具有相同的签名,即相同的参数个数,相同的参数类型和相同的返回值类型。我们回顾了普通委托之后再来看一下泛型委托的定义:

public delegate T 委托名<T>(T a, T b);

与之前不同的是,我们把int类型变成了万能的T类型,这样写的好处是什么呢?
可以想象,我们之前写了这样一个方法来处理加减乘除不同的计算方法:

    static void Calculate(Expression ex, int a, int b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }    

仔细的你会发现我们封装的这个方法有很大的局限性,假如我们某天要计算Double,float小数类型或者其他类型的加减乘除时,我们是不是又不得不重载多个不同参数类型的Calculate方法,即:

    static void Calculate(Expression ex, double a, double b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }

    static void Calculate(Expression ex, float a, float b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }

这样的话是不是代码又有重复了,那假设又几千种不同的类型要去计算呢?我们能不能只写一个方法就处理不同类型的加减乘除呢?这时,C#里有一个重要的工具:泛型的作用就体现出来了,我们可以把委托和方法定义成泛型的。代码如下:

    public delegate T Expression<T>(T a, T b);
    class Program
    {
        static void Main(string[] args)
        {
            Expression<int> add = (a, b) => a + b;
            Calculate(add, 10, 25);
            Console.ReadKey();
        }
        static void Calculate<T>(Expression<T> ex, T a, T b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }     
    }

我们只需在声明委托Expression<>时,为委托定义int类型就可以了,假如有一天,我要定义double类型,同理只需把Expression<int>换成Expression<double>即可,这样写是不是既节省了代码,又让Calculate方法的灵活性变高了。不管是lambda表达式还是泛型,微软可谓把DRY(Don't-repeat-yourself)原则发挥的淋漓尽致,其实微软早已为我们定义好了一套泛型委托供我们使用,以免我们在自己使用时还繁琐重复的去定义它,他们分别是Action,Func和Predicate

这是我在资料上摘取的这几个委托的区别:

(1). Action

       Action是无返回值的泛型委托。

 

   Action 表示无参,无返回值的委托

 

   Action<int,string> 表示有传入参数int,string无返回值的委托

 

   Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托

 

       Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托

 

   Action至少0个参数,至多16个参数,无返回值。

 (2). Func

   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

(3). Predicate

   predicate 是返回bool型的泛型委托

   predicate<int> 表示传入参数为int 返回bool的委托

   Predicate有且只有一个参数,返回值固定为bool

一般的需求下,我们就使用微软定义的委托就足够了,这样减少了我们对委托的重复定义,可能有部分初学者见到Func<>,Action<>这样的代码肯定会很懵比,这只是你对新东西陌生罢了,多结合实例敲几遍,自然就会用了,它们其实就是微软封装定义好了的委托,没有什么特别的。我们上面的代码也可以这样写:

    class Program
    {
        static void Main(string[] args)
        {
            Func<int,int,int> add = (a, b) => a + b;
            Calculate(add, 10, 25);
            Console.ReadKey();
        }
        static void Calculate<T, Y, U>(Func<T, Y, U> ex, T a, Y b)
        {
            Console.WriteLine(ex(a, b) + "\n");
        }
    }

这样写用Func就省去了定义委托这一步。

同样,其实在我们的webform,winform框架中,微软也给我们规范了一个委托的定义:

delegate void EvenHandler(object sender, EventArgs e);

都知道上面的object类是所有类型的基类,那EventArgs类呢?它其实就是所有包含事件数据类的基类

 

posted @ 2016-11-08 20:26  骇客HK  阅读(6572)  评论(4编辑  收藏  举报