黑马程序员-.NET基础之泛型

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------

 

泛型引例ArrayList

  相信大家在看杨中科老师基础视频中都不陌生个类ArrayList,我的基础测试中也有关于这个类运用的一道题。可见泛型是很基础同时又是很重要的一个知识点。ArrayList通用化是通过在类型与通用基类型Object之间进行强制转换来实现的:添加到ArrayList中的任何引用或值类型都将隐式地向上强制转换为Object;如果项是值类型,则添加时需要进行装箱操作,检索时需要进行拆箱操作。
ArrayList通用化有2个主要缺点:强制转换以及装箱和拆箱操作都会降低性能(特别是大型集合时);另一个限制是缺少编译时类型检查,因为所有项都强制转换为Object,所以在编译时无法防止客户端代码执行非法操作。

using System;
using System.Collections;
namespace CSharpPractice.ArrayList
{
    public class ArrayListTest
    {
        public static void Main()
        {
            //创建整型数组列表
            ArrayList list1 = new ArrayList();
            list1.Add(3);
            list1.Add(105);
            //显示整型数组列表中的值
            Console.WriteLine("整型数组列表ArrayList1的内容如下:");
            foreach (int x in list1)
            {
                Console.WriteLine(x);
            }

            //创建字符串型数组列表
            ArrayList list2 = new ArrayList();
            list2.Add("Hello");
            list2.Add("Friends");
            //显示字符串型数组列表中的值
            Console.WriteLine("字符串型数组列表ArrayList2的内容如下:");
            foreach (string s in list2)
            {
                Console.WriteLine(s);
            }

            //创建整数、字符串混合型数组列表
            ArrayList list3 = new ArrayList();
            list3.Add(11);       // 添加一个整数.
            list3.Add("字符串"); // 添加一个字符串
            int t = 0;
            // 求数组列表ArrayList3各元素之和
            Console.WriteLine("数组列表ArrayList3各元素之和为:");
            foreach (int x in list3) // 产生运行时错误:InvalidCastException
            {
                t += x;
            }
            Console.ReadLine();
        }
    }
}


 

引例List<T>

   与ArrayList相比,使用 List<T>时,必须为每个实例指定其具体的数据类型。这样将不再需要向上强制转换为System.Object以及装箱和拆箱操作,同时也使得编译器可以进行类型检查,从而解决了ArrayList通用化的2个主要问题,保证了程序的性能和健壮性。

using System;
using System.Collections;
using System.Collections.Generic;
namespace CSharpPractice.ListT
{
    public class ListTest
    {
        public static void Main()
        {
            //创建整型数组列表
            List<int> list1 = new List<int>();
            list1.Add(3);
            list1.Add(105);
            //显示整型数组列表中的值
            Console.WriteLine("整型数组列表ArrayList1的内容如下:");
            foreach (int x in list1)
            {
                Console.WriteLine(x);
            }

            //创建字符串型数组列表
            List<string> list2 = new List<string>();
            list2.Add("Hello");
            list2.Add("Friends");
            //显示字符串型数组列表中的值
            Console.WriteLine("字符串型数组列表ArrayList2的内容如下:");
            foreach (string s in list2)
            {
                Console.WriteLine(s);
            }

            // 试图创建整数、字符串混合型数组列表,失败!
            List<int> list3 = new List<int>();
            list3.Add(11);         // 添加一个整数.
            //list3.Add("字符串");  // 编译错误
            list3.Add(22);        //  添加另一个整数.
            int t = 0;
            Console.WriteLine("数组列表ArrayList3各元素之和为:");
            foreach (int x in list3)
            {
                t += x;
            }
            Console.WriteLine(t);
            Console.ReadLine();
        }
    }
}


 

一、泛型的概念与定义

    泛型类似于 C++ 模板,通过泛型可以定义类型安全的数据结构,而无须使用实际的数据类型。例如,通过定义泛型方法(static void Swap<T>(ref T lhs, ref T rhs)),可以重用数据处理算法,实现不同类型数据(例如int、double)的交换,而无需分别为int和double复制类型特定的代码(重载方法),从而显著提高性能并得到更高质量的代码。.NET Framework 2.0版类库提供一个新的命名空间 System.Collections.Generic,其中包含若干基于泛型的集合类。在泛型类的声明中,需要声明泛型参数,然后在泛型类的成员声明中,使用该泛型参数作为通用类型;而在创建泛型类的实例时,则需要与泛型参数对应的实际类型。

2.泛型类型参数

   在泛型类型定义中,必须通过指定尖括号中的类型参数来声明类型。类型参数实际上并不是特定类型,而只是类型占位符。在创建泛型类型的实例时,必须指定尖括号中的类型(可以是编译器识别的任何类型)
例如:
GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();
类型参数遵循下列命名准则
使用“T”作为描述性类型参数名的前缀,并使用描述性名称命名泛型类型参数。

using System;
using System.Collections.Generic;
namespace CSharpPractice.Generic
{
    public class GenericList<T>
    {
        // 嵌套类也通过泛型参数(<T>)定义.
        private class Node
        {   // T用于非泛型构造函数.
            public Node(T t)
            {
                next = null;
                data = t;
            }
            private Node next;
            public Node Next
            {
                get { return next; }
                set { next = value; }
            }
            // T作为数据类型私有成员.
            private T data;
            // T作为属性返回类型.
            public T Data
            {
                get { return data; }
                set { data = value; }
            }
        }
        private Node head;
        public GenericList()  // 构造函数
        {   // 堆栈(后进先出)初始化
            head = null;
        }
        // T作为方法的参数类型:
        public void AddHead(T t)
        { // 新结点加入到当前堆栈的头部,并且成为head
            Node n = new Node(t);
            n.Next = head;
            head = n;
        }
        public IEnumerator<T> GetEnumerator()
        {  // 从头到尾依次输出堆栈中的值
            Node current = head;
            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }
        }
    }
    class TestGenericList
    {
        static void Main()
        {  // int是类型参数
            GenericList<int> list = new GenericList<int>();
            Console.WriteLine("0~9 十个整数形成堆栈");
            for (int x = 0; x < 10; x++)
            {  // 0~9 十个整数形成堆栈
                list.AddHead(x);
            }
            Console.WriteLine("堆栈(后进先出)内容如下:");
            foreach (int i in list)
            {   // 输出堆栈内容9~0
                Console.Write(i + " ");
            }
            Console.ReadLine();
        }
    }
}


 

二、泛型接口

   在泛型类的设计中,通常也把泛型类共通要实现的方法、委托或事件的签名封装为泛型接口,然后在实现这些泛型接口的泛型类中实现这些方法等,下面是泛型接口示例。

using System;
using System.Collections.Generic;
namespace CSharpPractice.GenericInterface
{
    class Program
    {
        static void Main()
        {
            int[] arr = { 0, 1, 2, 3, 4 };
            List<int> list = new List<int>();

            for (int x = 5; x < 10; x++)
            { // 形成列表 5、6、7、8、9
                list.Add(x);
            }

            Console.WriteLine("输出数组列表ArrayList的内容:");
            ProcessItems<int>(arr);
            Console.WriteLine("输出列表List的内容:");
            ProcessItems<int>(list);
            Console.ReadLine();

        }

        static void ProcessItems<T>(IList<T> coll)
        {
            foreach (T item in coll)
            {
                Console.Write(item.ToString() + " ");
            }
            Console.WriteLine();
        }
    }
}

 

三、泛型方法

泛型方法是使用类型参数声明的方法。编译器能够根据传入的方法实参推断类型形参。

using System;
namespace CSharpPractice.GenericMethod
{
    public class GenericMethod
    {
        //声明泛型方法:两者交换
        static void Swap<T>(ref T lhs, ref T rhs)
        {
            T temp;
            temp = lhs;
            lhs = rhs;
            rhs = temp;
        }
        public static void Main()
        {
            int a = 1;
            int b = 2;
            Console.WriteLine("Original value, a = {0} , b = {1}", a, b);
            //调用泛型方法:指定泛型参数的类型
            Swap<int>(ref a, ref b);
            Console.WriteLine("After swapping, a = {0} , b = {1}", a, b);
            //调用泛型方法:可以省略类型参数,编译器将推断出该参数
            double c = 1.1d;
            double d = 2.2d;
            Console.WriteLine("Original value, c = {0} , d = {1}", c, d);
            Swap(ref c, ref d);
            Console.WriteLine("After swapping, c = {0} , d = {1}", c, d);
            Console.ReadLine();
        }
    }
}

 

 

四、泛型委托和泛型事件

通过泛型类型参数,同样可以定义泛型委托。通过指定类型参数,可以引用泛型委托
在泛型类内部定义的委托,可以使用泛型类的泛型类型参数
基于泛型委托,可以定义泛型事件。此时发送方参数可以为强类型,不再需要强制转换成Object,或反向强制转换,下面给出泛型委托和事件示例。

using System;
namespace CSharpPractice.GenericIntegrated
{
    // 类型参数T使用尖括号< >括起.
    public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
    {
        protected Node head;
        protected Node current = null;
        // 嵌套类也是关于T的泛型类
        protected class Node
        {
            public Node next;
            private T data;    // T作为私有成员数据类型
            public Node(T t)  // T用于非泛化构造函数
            {
                next = null;
                data = t;
            }
            public Node Next
            {
                get { return next; }
                set { next = value; }
            }
            public T Data       // T 作为属性的返回类型
            {
                get { return data; }
                set { data = value; }
            }
        }
        public GenericList()  // 构造函数
        {
            head = null;
        }
        public void AddHead(T t)    // T 作为成员参数类型
        {   //新结点加入到当前列表的头部,并且成为head
            Node n = new Node(t);
            n.Next = head;
            head = n;
        }
        // Implementation of the iterator
        public System.Collections.Generic.IEnumerator<T> GetEnumerator()
        {   // 从头到尾依次遍历列表中每个节点
            Node current = head;
            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }
        }
        // IEnumerable<T>继承自IEnumerable,所以该类必须同时实现 
        // GetEnumerator的泛型和非泛型方法。通常非泛型方法可以通过
        // 直接调用泛型方法来简化实现过程
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public class SortedList<T> : GenericList<T> where T : System.IComparable<T>
    {
        // 一个简单的、未经优化的排序算法:将列表元素从小到大排序
        public void BubbleSort()  // 冒泡排序
        {
            if (null == head || null == head.Next)
            {
                return;
            }
            bool swapped;

            do
            {
                Node previous = null;
                Node current = head;
                swapped = false;

                while (current.next != null)
                {   //  SortedList类在IEnumerable<T>上约束???
                    //  Because we need to call this method, the SortedList
                    //  class is constrained on IEnumerable<T>
                    if (current.Data.CompareTo(current.next.Data) > 0)
                    {
                        Node tmp = current.next;
                        current.next = current.next.next;
                        tmp.next = current;

                        if (previous == null)
                        {
                            head = tmp;
                        }
                        else
                        {
                            previous.next = tmp;
                        }
                        previous = tmp;
                        swapped = true;
                    }
                    else
                    {
                        previous = current;
                        current = current.next;
                    }
                }
            } while (swapped);
        }
    }

    // 定义一个简单的类Person来实现IComparable<T> , 
    // 类Person本身作为类型参数。
    public class Person : System.IComparable<Person>
    {
        string name;  // 姓名
        int age;     //  年龄

        public Person(string s, int i)
        {
            name = s;
            age = i;
        }

        // 对列表元素根据年龄排序.
        public int CompareTo(Person p)
        {
            return age - p.age;
        }

        public override string ToString()
        {
            return name + ":" + age;
        }

        // 实现Equals方法,判断两个人是否同龄.
        public bool Equals(Person p)
        {
            return (this.age == p.age);
        }
    }

    class TestSortedList
    {
        static void Main()
        {
            // 声明和实例化一个新的泛型SortedList类.
            //  Person 作为类型参数.
            SortedList<Person> list = new SortedList<Person>();

            // 初始化Person对象,对name和age赋初值.
            string[] names = new string[] 
        { 
            "刘一", 
            "陈二", 
            "张三", 
            "李四", 
            "王五", 
            "姚六", 
        };

            int[] ages = new int[] { 45, 19, 28, 23, 18, 79 };

            // 形成由name和age组成的列表.
            for (int x = 0; x < 6; x++)
            {
                list.AddHead(new Person(names[x], ages[x]));
            }

            // 打印无序列表.
            Console.WriteLine("初始(无序)列表为:");
            foreach (Person p in list)
            {
                Console.Write(p.ToString() + "  ");
            }
            Console.WriteLine();

            // 列表排序.
            list.BubbleSort();

            // 打印有序列表.
            Console.WriteLine("\n按年龄排好序的列表为:");
            foreach (Person p in list)
            {
                Console.Write(p.ToString() + "  ");
            }
            Console.ReadLine();
        }
    }
}

 

 

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值