泛型

概念:


类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。


优点:


使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。


实现:


关于泛型数据类型中使用的类型的信息可在运行时通过反射获取。


实例演示:


我们事先一个最简单的冒泡排序(Bubble Sort)算法,我们可以是这样实现的:


<span style="font-family:SimSun;font-size:18px;">  public class SortHelper
    {
        public void BubbleSort(int[] array)
        {
            int length = array.Length;

            for (int i = 0; i <= length - 2; i++)
            {
                for (int j = length - 1; j >= 1; j--)
                {

                    // 对两个元素进行交换
                    if (array[j] < array[j - 1])
                    {
                        int temp = array[j];
                        array[j] = array[j - 1];
                        array[j - 1] = temp;
                    }
                }
            }
        }
    }</span>

测试:


<span style="font-family:SimSun;font-size:18px;">    class Program
    {
        static void Main(string[] args)
        {
            SortHelper sorter = new SortHelper();

            int[] array = { 8, 1, 4, 7, 3 };

            sorter.BubbleSort(array);

            foreach (int i in array)
            {
                Console.Write("{0} ", i);
            }

            Console.WriteLine();
            Console.ReadKey();

        }

    }</span>

我们发现它是可以使用的,而后,我们需要对一个byte类型的数组进行排序,而我们上面的排序算法只能接受一个int类型的数组,尽管我们知道他们是完全兼容的。因为byte类型是int类型的一个自己,但C#是一个强类型的语言,我们无法再一个接受int数组类型的地方传入一个byte数组。


<span style="font-family:SimSun;font-size:18px;">public class SortHelper {
    public void BubbleSort(int[] array) {
        int length = array.Length;

        for (int i = 0; i <= length - 2; i++) {
            for (int j = length - 1; j >= 1; j--) {

                // 对两个元素进行交换
                if (array[j] < array[j - 1]) {
                    int temp = array[j];
                    array[j] = array[j - 1];
                    array[j - 1] = temp;
                }
            }
        }
    }


    public void BubbleSort(byte[] array) {
        int length = array.Length;

        for (int i = 0; i <= length - 2; i++) {
            for (int j = length - 1; j >= 1; j--) {

                // 对两个元素进行交换
                if (array[j] < array[j - 1]) {
                    int temp = array[j];
                    array[j] = array[j - 1];
                    array[j - 1] = temp;
                }
            }
        }
    }
}
</span>

这样看来,我们开发完成后,看似是完成了任务,但是按照敏捷软件开发的思想,不要过早地进行抽象和应对变化,而对话第一次出现时,使用最快额方法解决它,当变化第二次出现时,再进行更好的架构和设计。这样的目的是为了避免过度设计,因为很有可能第二次变化永远也不会出现,而你花费了大量的时间制造了一个用于也用不到的“完美设计”。


当然,我们需要对一个char类型的数组继续排序,我们当然可以仿照byte类型数组的做法。继续采用复制粘贴,修改一下方法的签名。


我们仔细地对照两个方法,会发现这两个方法的实现完全一样,除了方法的签名不同以外,,没有任何的区别。我们就这样想,我们将上面的方法体现为一个模板,将他的方法签名视为一个占位符,因为它是一个占位符,所以它可以代表任何的类型。我们写出新的代码:


<span style="font-family:SimSun;font-size:18px;">  public class SortHelper3<T> where T:IComparable 
    {
        public void BubbleSort(T[] array)
        {
            int length = array.Length;

            for (int i = 0; i <= length - 2; i++)
            {
                for (int j = length - 1; j >= 1; j--)
                {

                    // 对两个元素进行交换
                    if (array[j] < array[j - 1])
                    {
                        T temp = array[j];
                        array[j] = array[j - 1];
                        array[j - 1] = temp;
                    }
                }
            }
        }
    }</span>

以上是我们用占位符替换了先前各个类型。其实用上面的代码是会出错的,因为T类型,编译无法确定是否可以进行“<"比较,所以会报错,这个不用管它。现在我们看代码就清爽了很多,但是我们有发现了一个问题:当我们定义一个类,而这个类需要引用它本身以外的其他类型是,我们需要定义有参数的构造函数,然后将它需要的参数从构造函数中传进来。因此,我们要这样写 where T:  Class,new(),这里就是限定了T的类型。


实例二:类型参数约束


上述的代码编译都通过不了,为什么?举个简单的例子,我们有一个书,书有两个字段:1、int类型ID,2、string类型的Title。我们怎么比较他们的大小呢?因为我们不知道要按照int比还是string进行比较。


我们用代码实现这样问题:


比较的接口:


<span style="font-family:SimSun;font-size:18px;">    public interface IComparable
    {
        int CompareTo(object obj);
    }</span>

Books这个类实现该接口:


<span style="font-family:SimSun;font-size:18px;">    public class Book :IComparable 
    {
        private int id;
        private string title;

        public Book() { }

        public Book(int id, string title)
        {
            this.id = id;
            this.title = title;
        }

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public string Title
        {
            get { return title; }
            set { title = value; }
        }

        public int CompareTo(object obj)
        {
            Book book2 = (Book)obj;
            return this.Id.CompareTo(book2.Id);
        }
    }</span>


在这个里面我们用到了CompareTo这个方法中,我们用Id进行比较的,而且,我们可以注意到,我们没有在CompareTo()方法中去比较当前的Book实例的ID与传进来的Book实例的ID,而是将对他们的比较委托给了int类型,因为int类型也实现了IComparable接口。int32类型,实现了CompareTo方法,因此为了获得Book类型,我们需要在方法中进行一个向下强制转换(这个还要好好体会),我们重写SortHelper:


<span style="font-family:SimSun;font-size:18px;"> public class SortHelper3<T> where T : IComparable
    {
        public void BubbleSort(T[] array)
        {
            int length = array.Length;

            for (int i = 0; i <= length - 2; i++)
            {
                for (int j = length - 1; j >= 1; j--)
                {

                    // 对两个元素进行交换
                    if (array[j].CompareTo(array[j - 1]) < 0)
                    {
                        T temp = array[j];
                        array[j] = array[j - 1];
                        array[j - 1] = temp;
                    }
                }
            }
        }
    }</span>


测试:


<span style="font-family:SimSun;font-size:18px;">   static void Main(string[] args)
        {
                Book[] bookArray = new Book[2];

                Book book1 = new Book(124, ".Net之美");
                Book book2 = new Book(45, "C# 3.0揭秘");

                bookArray[0] = book1;
                bookArray[1] = book2;

                SortHelper3<Book> sorter = new SortHelper3<Book>();
                sorter.BubbleSort(bookArray);

                foreach (Book b in bookArray)
                {
                    Console.WriteLine("Id:{0}", b.Id);
                    Console.WriteLine("Title:{0}\n", b.Title);
                }

            }

        }    </span>


没有问题了。


实例三:泛型方法


我们都知道当我们定义一个泛型类的话,该类下面所有的方法都会受到影响,而我们只需要一个防反射杭冕加上类型参数T,这个时候,我们就要想办法吧类型参数T加到方法上,为了降低T作用的范围。


泛型方法的代码这样写:


<span style="font-family:SimSun;font-size:18px;">public class SuperCalculator{
    // CODE:其他实现略

    public void SpeedSort<T>(T[] array) where T : IComparable {
        // CODE:实现略
    }
}</span>


泛型方法的调用可以这样写:


<span style="font-family:SimSun;font-size:18px;">SuperCalculator calculator = new SuperCalculator();
calculator.SpeedSort<Book>(bookArray);</span>

也可以这样写:


<span style="font-family:SimSun;font-size:18px;">calculator.SpeedSort(bookArray);</span>

总结:


我们学习东西的时候,一定要动手去做,才能学到东西,有时候光靠看和想是不行的,我们应该做的是在实践中学会思考。


参考资料:http://www.360doc.com/content/11/1116/11/130258_164743728.shtml








评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值