特殊的类——集合与泛型(C#)

C#常用泛型集合 C#泛型集合 作者:云都小生 概述 之前已经整理了泛型和集合的资料,今天来刷一下两个C#提供的常用泛型集合——List<>和Dictionary<>。 List <> 使用List<>泛型集合,需要引入System.Collections.Generic(命名空间) List<>是ArrayList的泛... 阅读详情

集合就像是一种容器,是用于存储、获取、操作对象的容器。如果集合中不使用泛型,意味着集合中可以添加任意类型的对象。当用户需要具体用到某一个类型时,必须强制进行类型转换才可以得到,但是这样就可能引发异常。

一、认识集合

1、集合类的概念

集合(Collection)类是专门用于数据存储和检索的类。

2、集合类的特点

(1)集合类定义为System.Collections或System.Collections.Generic命名空间的一部分。

(2)大多数集合类都派生自ICollection、IComparer、IEnumerable、IList、IDictionary和IDictionaryEnumerator接口以及它们的等效泛型接口。

(3)使用泛型集合类可以提供更高的类型安全性,在某些情况下还可以提供更好的性能,尤其是在存储值类型时,这些优势会体现得更明显。

二、常用集合类型

常用的集合类型有动态数组(ArrayList类)、堆栈(Stack类)、Queue类和Hashtable类。

1、动态数组

动态数组(ArrayList)代表了可被单独索引的对象的有序集合。它基本上可以替代一个数组。但是,与数组不同的是,用户可以使用索引在指定的位置添加和移除项目,动态数组会自动重新调整它的大小。它也允许在列表中进行动态内存分配、增加、搜索、排序各项。

1、ArrayList类的方法和属性

ArrayList类的属性
属性描述
Capacity获取或设置ArrayList可以包含的元素个数
Count获取ArrayList中实际包含的元素个数
IsFixedSize获取一个值,表示ArrayList是否具有固定大小
IsReadOnly获取一个值,表示ArrayList是否只读
Item获取或设置指定索引处的元素

ArrayList类的方法
序号方法名&描述
1public virtual int Add(object value);在ArrayList的末尾添加一个对象
2public virtual void AddRange(ICollection c);在ArrayList的末尾添加Icollection的元素
3public virtual void Clear();从ArrayList中移除所有的元素
4public virtual bool Contains(object item);判断某个元素是否在ArrayList中
5public virtual ArrayList GetRange(int index, int count);返回一个ArrayList,表示源ArrayList中元素的子集
6public virtual int IndexOf(object);返回某个值在ArrayList中第一次出现的索引,索引从零开始。
7public virtual void Insert(int index, object value);在ArrayList的指定索引处,插入一个元素
8public virtual void InsertRange(int index, ICollection c);在ArrayList的指定索引处,插入某个集合的元素
9public virtual void Remove(object obj);从ArrayList中移除第一次出现的指定对象
10public virtual void RemoveAt(int index);移除ArrayList的指定索引处的元素
11public virtual void RemoveRange(int index, int count);从ArrayList中移除某个范围的元素
12public virtual void Reverse(); 逆转ArrayList中元素的顺序
13public virtual void SetRange(int index, ICollection c); 复制某个集合的元素到ArrayList中某个范围的元素上
14public virtual void Sort(); 对ArrayList中的元素进行排序
15public virtual void TrimToSize(); 设置容量为ArrayList中元素的实际个数

2、ArrayList类中元素的添加

编写程序,创建ArrayList实例,使其固定大小为5,通过Add方法对其添加5个元素,再通过AddRange方法对其添加一个数组,然后遍历所有数元素。

using System;
using System.Collections;   //在命名空间进行引用
namespace Project1
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayList al = new ArrayList(5);  //创建ArrayList的实例,使其固定大小为5
            // ArrayList的好处是,长度不固定,类型随意
            //数组的长度是固定的,不能更改的,类型单一,只能为其中的一种
            Console.WriteLine("------------Count属性----------------");
            Console.WriteLine("查看ArrayList中实际包含的元素个数:{0}",al.Count);
            Console.WriteLine("-------------Add方法-----------------");
            //Console.WriteLine("al初始化之后有{0}个元素",al.Count);//使用Count属性,查看ArrayList中实际包含的元素个数。
            //Add方法用于向ArrayList中添加单个元素,每次只能添加一个
            al.Add(110);     //整数类型
            al.Add('M');    //字符类型
            al.Add("HelloWorld");  //string类型
            al.Add(3.14);    //浮点类型
            al.Add(24L);    //长整型
            Console.WriteLine("使用Add方法添加5个元素之后,元素的个数:",al.Count);
            Console.WriteLine("------------AddRange方法--------------");//AddRange方法用于一次性向ArrayList中添加多个元素,可以是一个数组           
            string[] myStringAL = { "张三", "李四", "王五", "赵六" };//定义字符串数组
            al.AddRange(myStringAL);
            Console.WriteLine("使用AddRange方法添加4个元素后,元素的个数:{0}",al.Count);
            Console.WriteLine("--------------遍历集合----------------");
            //遍历集合元素
            //引用类型 string object类是所有类型的基类
            foreach (object outstring in al)   //首先定义一个任意类型的变量object,
            {
                Console.Write(outstring+"\t");  //按行来输出
            }
            Console.WriteLine();
        }
    }

}

3、ArrayList类中元素的删除

using System;
using System.Collections;   //在命名空间进行引用
namespace Project2
{
    class Program
    {
        static void Main(string[] args)
        {
            //元素的删除有四种方法
            //Remove()
            ArrayList al = new ArrayList();  //实例化对象
            al.Add("小组评分:");
            al.Add(88.5);
            al.Add("小组成员:");
            string[] myStringAL = { "张三", "李四", "王五", "赵六" };
            al.AddRange(myStringAL);        
            foreach (object outArry in al)
            {
                Console.Write(outArry+"\t");
            }
            Console.WriteLine("\n------------Remove方法----------------");//Remove(值)            
            Console.WriteLine("指定对象,移除张三");
            al.Remove("张三");
            foreach (object outArry in al)
            {
                Console.Write(outArry + "\t");
            }
            Console.WriteLine("\n-----------RemoveAt方法---------------");//RemoveAt(索引值)            
            Console.WriteLine("指定索引值,移除李四");
            al.RemoveAt(3);
            foreach (object outArry in al)
            {
                Console.Write(outArry + "\t");
            }
            Console.WriteLine("\n-----------RemoveRange方法------------");//RemoveRange(开始索引值,要删除的个数)            
            Console.WriteLine("指定某个范围,移除王五和赵六");
            al.RemoveRange(3, 2);//从第三元素开始,删除两个元素
            foreach (object outArry in al)
            {
                Console.Write(outArry + "\t");
            }
            Console.WriteLine("\n-----------Clear方法------------");           
            Console.WriteLine("清除所有元素");
            al.Clear();
            foreach (object outArry in al)
            {
                Console.Write(outArry + "\t");
            }
            Console.WriteLine();
        }
    }
}

4、ArrayList类中元素的遍历和查找 

using System;
using System.Collections;
namespace Project3
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayList al = new ArrayList();
            al.Add("数组:");
            int[] alInArry = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            al.AddRange(alInArry);
            al.Add("字符串:");
            string[] alStringArry = { "张三", "李四", "王五", "赵六","李四" };
            al.AddRange(alStringArry);
            Console.WriteLine("------------遍历元素----------------");
            foreach (object outArry in al)
            {
                Console.Write(outArry+"  ");
            }
            Console.WriteLine("\n------------查找元素----------------");
            Console.WriteLine("\n-----------IndexOf方法--------------");
            //IndexOf(要查找的元素),返回一个首次出现的索引整型值,如果查找不到,返回-1
            Console.WriteLine(al.IndexOf("李四"));
            Console.WriteLine("\n----------LastIndexOf方法-----------");
            //LastIndexOf(要查找的元素),返回一个最后一次出现的索引整型值,否则返回-1
            Console.WriteLine(al.LastIndexOf("李四"));
        }
    }
}

2、堆栈(Stack)类

堆栈(Stack)代表了一个后进先出的对象集合。当用户需要对各项进行后进先出的访问时,则使用堆栈。当用户在列表中添加一项时,称为推入元素,当用户从列表中移除一项时,称为弹出元素。

Stack类的方法
序号方法名&描述
1

public virtual void Clear();

从Stack中移除所有的元素

2

public virtual bool Contains(object obj);

判断某个元素是否在Stack中

3

public virtual object Peek();

返回在Stack的项目的对象,但不移除它

4

public virtual object Pop();

移除并返回在Stack的顶部的对象

5

public virtual void Push(object obj);

向Stack的顶部添加一个对象

6

public virtual object[] ToArray();

复制Stack到一个新的数组中

编写程序,实现堆栈的进出

代码如下:

using System;
using System.Collections;
namespace Project4
{
    class Program
    {
        static void Main(string[] args)
        {
            Stack st = new Stack();    //实例化st的对象
            Console.WriteLine("------------Push方法----------------");
            Console.WriteLine("向堆栈的顶部添加四个对象");
            st.Push('a');
            st.Push('b');
            st.Push('c');
            st.Push('d');
            Console.WriteLine("------------遍历Stack---------------");
            foreach (char c in st)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine();
            Console.WriteLine("向堆栈的顶部添加两个对象");
            st.Push('V');
            st.Push('H');
            foreach (char c in st)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine("\n------------Peek方法----------------");
            Console.WriteLine("堆栈顶部的对象:{0}",st.Peek());
            Console.WriteLine("--------------Pop方法---------------");
            Console.WriteLine("移除堆栈顶部的对象:{0}",st.Pop());
            foreach (char c in st)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine("\n移除堆栈顶部的对象:{0}", st.Pop());
            foreach (char c in st)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine();
        }
    }
}

运行结果如下:

------------Push方法----------------
向堆栈的顶部添加四个对象
------------遍历Stack---------------
d c b a
向堆栈的顶部添加两个对象
H V d c b a
------------Peek方法----------------
堆栈顶部的对象:H
--------------Pop方法---------------
移除堆栈顶部的对象:H
V d c b a
移除堆栈顶部的对象:V
d c b a

3、队列(Queue)类

队列(Queue)代表了一个先进先出的对象集合。当需要对各项进行先进先出的访问时,则使用队列。在列表中添加一项时,称为入队,从列表中移除一项时,称为出队。

Queue类的方法
序号方法名&描述
1public virtual void Clear();从Queue中移除所有的元素
2public virtual bool Contains(object obj);判断某个元素是否在Queue中
3public virtual object Dequeue();移除并返回在Queue的开头的对象
4public virtual void Enqueue(object obj); 向Queue的末尾添加一个对象
5public virtual object[] ToArray(); 复制Queue到一个新的数组中
6public virtual void TrimToSize(); 设置容量为Queue中元素的实际个数

编写程序 ,实现队列的进出。

using System;
using System.Collections;
namespace Project5
{
    class Program
    {
        static void Main(string[] args)
        {
            Queue q = new Queue();     //创建一个队列
            Console.WriteLine("------------Enqueue方法----------------");
            Console.WriteLine("向队列的末尾依次添加对象");
            q.Enqueue('a');
            q.Enqueue('b');
            q.Enqueue('c');
            q.Enqueue('d');
            Console.WriteLine("--------------遍历队列-----------------");
            foreach (char c in q)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine("\n向队列的末尾再添加两个对象");
            q.Enqueue('V');
            q.Enqueue('H');
            foreach (char c in q)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine();
            Console.WriteLine("------------Dequeue方法----------------");
            Console.WriteLine("移除队列开头的两个对象");
            char ch = (char)q.Dequeue();
            Console.WriteLine("移除开头第一个对象: {0}", ch);
            ch = (char)q.Dequeue();
            Console.WriteLine("移除开头第二个对象: {0}", ch);
            Console.WriteLine("--------------遍历队列-----------------");
            foreach (char c in q)
            {
                Console.Write(c + " ");
            }
            Console.WriteLine();
        }
    }
}

运行结果如下:

------------Enqueue方法----------------
向队列的末尾依次添加对象
--------------遍历队列-----------------
a b c d
向队列的末尾再添加两个对象
a b c d V H
------------Dequeue方法----------------
移除队列开头的两个对象
移除开头第一个对象: a
移除开头第二个对象: b
--------------遍历队列-----------------
c d V H

4、哈希表(Hashtable)类

Hashtable被称作哈希表,该哈希表将映射到相应的值。用于处理和表现类似key/value的键值对,其中,key通常可用来快速查找,同时key是区分大小写的;value用于存储对应于key的值。

Hashtable中key/value键值对均为object类型,所以Hashtable可以支持任何类型的key/value键值对。Hashtable中的每个元素是一个存储在DictionaryEntry对象中的键值对。

1、Hashtable类的方法和属性

Hashtable类的属性
属性描述
Count获取Hashtable中包含的键值对个数
IsFixedSize获取一个值,表达Hashtable是否具有固定大小
IsReadOnly获取一个值,表达Hashtable是否只读
Item获取或设置与指定的键相关的值
Keys获取一个ICollection,包含Hashtable中的键
Values获取一个ICollection,包含Hashtable中的键

Hashtable类的方法
序号方法名&描述
1public virtual void Add(object key, object, value);向Hashtable添加一个带有指定的键和值的元素
2public virtual void Clear();从Hashtable中移除所有的元素
3public virtual void ContainsKey(object key);判断Hashtable是否包含指定的键
4public virtual void ContainsValue(object value);判断Hashtable是否包含指定的值
5public virtual void Remove(object key);从Hashtable中移除带有指定的键的元素

2、Hashtable类中元素的添加

编写程序,新建一个Hashtable对象,向其中添加四个元素。

using System;
using System.Collections;
namespace Project6
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            Console.WriteLine("------------元素添加方法一----------------");
            ht.Add(1, "星期一");
            ht.Add(2, "星期二");
            ht.Add(3, "星期三");
            ICollection key = ht.Keys;   //获取键值
            foreach (object k in key)
            {
                Console.WriteLine(k + ": " + ht[k]);
            }
            //用此种方法对Hashtable去增加元素时,应该注意:
            //如果对应的键key,存值,只达到一种重新赋值的结果
            //如果不存在,才会增加对应的键值对
            Console.WriteLine("------------元素添加方法二----------------");
            ht[4] = "星期四";
            ht[1] = "星期五";
            foreach (object k in key)
            {
                Console.WriteLine(k + ": " + ht[k]);
            }
            Console.WriteLine("---------------Count属性------------------");
            Console.WriteLine("哈希表包含键值对的个数:{0}", ht.Count);
        }
    }
}

运行结果如下:

------------元素添加方法一----------------
3: 星期三
2: 星期二
1: 星期一
------------元素添加方法二----------------
4: 星期四
3: 星期三
2: 星期二
1: 星期五
---------------Count属性------------------
哈希表包含键值对的个数:4

3、Hashtable元素的遍历

数组的遍历通常都采用的是for循环语句,但是对于集合的遍历都是采用foreach语句。在C#语言中的foreach语句需要集合中每个元素的类型。对于IDictionary接口是键/值对的非泛型集合的基接口,而每个元素都是键/值对,并存储在DictionaryEntry对象中,因此元素类型即不是键的类型,也不是值的类型,而是DictionaryEntry类型。

编写程序 ,新建Hashtable的对象,向其中添加四个元素,使用foreach进行遍历。

using System;
using System.Collections;

namespace Project7
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            ht.Add(1, "星期一");
            ht.Add(2, "星期二");
            ht.Add(3, "星期三");
            ht[4] = "星期四";
            Console.WriteLine("-------------方法一------------");
            foreach (DictionaryEntry obj in ht)
            {
                Console.WriteLine("键为:{0};值为:{1}",obj.Key,obj.Value);
            }
            Console.WriteLine("-------------方法二------------");
            foreach (object obj in ht.Keys)  //键的集合
            {
                Console.WriteLine("键为:{0};值为:{1}", obj, ht[obj]);
            }
        }
    }
}

运行结果如下:

-------------方法一------------
键为:4;值为:星期四
键为:3;值为:星期三
键为:2;值为:星期二
键为:1;值为:星期一
-------------方法二------------
键为:4;值为:星期四
键为:3;值为:星期三
键为:2;值为:星期二
键为:1;值为:星期一

4、Hashtable元素的删除

编写程序,新建Hashtable的对象,向其中添加四个元素,然后进行删除。

using System;
using System.Collections;

namespace Project8
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            ht.Add("01", "星期一");
            ht.Add("02", "星期二");
            ht.Add("03", "星期三");
            ht.Add("04", "星期四");
            foreach (DictionaryEntry de in ht)
            {
                Console.WriteLine("键为{0};值为{1}",de.Key,de.Value);
            }
            Console.WriteLine("-------------Remove方法------------");
            Console.WriteLine("移除哈希表中指定的键的元素");
            ht.Remove("04");
            foreach (DictionaryEntry de in ht)
            {
                Console.WriteLine("键为{0};值为{1}", de.Key, de.Value);
            }
            Console.WriteLine("\n-------------Clear方法------------");
            Console.WriteLine("从 Hashtable 中移除所有的元素");
            ht.Clear();
            foreach (DictionaryEntry de in ht)
            {
                Console.WriteLine("键为{0};值为{1}", de.Key, de.Value);
            }
        }
    }
}

运行结果如下:

键为02;值为星期二
键为03;值为星期三
键为04;值为星期四
键为01;值为星期一
-------------Remove方法------------
移除哈希表中指定的键的元素
键为02;值为星期二
键为03;值为星期三
键为01;值为星期一

-------------Clear方法------------
从 Hashtable 中移除所有的元素

5、Hashtable元素的查找

Hashtable中键与值成对存在,键是唯一的,不能重复查找元素的时候,用户往往是依据键去查找值的。

using System;
using System.Collections;

namespace Project9
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable ht = new Hashtable();
            ht.Add(1, "星期一");
            ht.Add(2, "星期二");
            ht.Add(3, "星期三");
            ht.Add(4, "星期四");
            foreach (DictionaryEntry de in ht)
            {
                Console.WriteLine("键为{0};值为{1}", de.Key, de.Value);
            }
            Console.WriteLine("-------------ContainsKey------------");
            Console.WriteLine("判断 Hashtable 是否包含的键:3");
            if (ht.ContainsKey(3)) Console.WriteLine("存在该键");
            else Console.WriteLine("不存该键");
            Console.WriteLine("------------ContainsValue-----------");
            Console.WriteLine("判断 Hashtable 是否包含的值:{0}",ht[1]);
            if (ht.ContainsValue("星期一")) Console.WriteLine("存在改值");
            else Console.WriteLine("不存该值");
        }
    }
}

运行结果如下:

键为4;值为星期四
键为3;值为星期三
键为2;值为星期二
键为1;值为星期一
-------------ContainsKey------------
判断 Hashtable 是否包含的键:3
存在该键
------------ContainsValue-----------
判断 Hashtable 是否包含的值:星期一
存在改值

三、泛型

泛型(Generics)是将类型作为参数传递给类、结构、接口和方法,这些参数通常被称为占位符、是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。

1、泛型的概述

泛型是允许用户延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候再进行确认。换句话说,泛型允许用户编写一个可以与任何数据类型一起工作的类或方法。

用户可以通过数据类型的替代参数编写类或方法的规范。当编译器遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。

编写程序,创建一个泛型类MyGenericArray,直到实际使用类中成员时,再确定成员的数据类型。

using System;
namespace Project10
{
    public class MyGenericArray<T>       //创建泛型类
    {
        //定义未知类型的数组array
        private T[] array;
        //构造函数用于处理指定的数据类型
        public MyGenericArray(int size)
        {
            array = new T[size + 1];
        }
        //获取数组元素
        public T GetItem(int index)
        {
            return array[index];
        }
        //为数组元素赋值
        public void SetItem(int index, T value)
        {
            array[index] = value;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // 声明一个整型数组
            MyGenericArray<int> intArray = new MyGenericArray<int>(5);
            // 设置值
            for (int arr = 0; arr < 5; arr++)
            {
                intArray.SetItem(arr, arr * 2);
            }
            // 获取值
            for (int arr = 0; arr < 5; arr++)
            {
                Console.Write(intArray.GetItem(arr) + " ");
            }
            Console.WriteLine();
            // 声明一个字符数组
            MyGenericArray<char> charArray = new MyGenericArray<char>(5);
            // 设置值
            for (int arr = 0; arr < 5; arr++)
            {
                charArray.SetItem(arr, (char)(arr + 97));
            }
            // 获取值
            for (int arr = 0; arr < 5; arr++)
            {
                Console.Write(charArray.GetItem(arr) + " ");
            }
            Console.WriteLine();
        }
    }
}

运行结果:

2、泛型的特点

泛型是一种增加程序功能的技术,具体表现在以下几个方面。

(1)泛型为开发者提供了一种高性能的编程方式,能够提高代码的重用性,并允许开发者编写非常有效的解决方案。

(2)使用泛型可以提高性能,其中一个显著的改进是.NET框架组件,不会在值类型上使用装箱(Boxing);使用泛型类的另一个令人惊讶的特性是可以跟踪强数据类型定义。

(3)泛型类和泛型方法同时具备可重用性、类型安全和效率高等特点,它通常用在集合或者在集合上运行的方法中。

(4)用户可以对泛型类进行约束以访问特定数据类型的方法。

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

(6)用户可以创建泛型集合类。.NET框架类库在System.Collections.Generic命名空间中包含一些新的泛型集合类。用户可以使用这些泛型集合类来替代System.Collections中的集合类。

3、类型参数T

类型参数T是用来定义泛型类时的占位符,T并不是一种类型,它仅代表某种可能的类型。在定义时,T出现 的位置可以在使用时用任何类型来代替。

编写程序,使用类型参数T来代表各种数据类型。

using System;
using System.Collections.Generic;
namespace Project11
{
    //定义泛型类
    public class TGeneric<T>
    {
        void Exp(T input)
        {

        }
    }
    //自定义类
    public class MyClass
    { }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化TGeneric的对象为char、int、string类型
            TGeneric<char> charTG = new TGeneric<char>();
            Console.WriteLine("实例化类型为char的TGeneric的charTG成功");
            TGeneric<int> intTG = new TGeneric<int>();
            Console.WriteLine("实例化类型为int的TGeneric的intTG成功");
            TGeneric<string> stringTG = new TGeneric<string>();
            Console.WriteLine("实例化类型为string的TGeneric的stringTG成功");
            //实例化TGeneric的对象为MyClass类类型
            TGeneric<MyClass> classTG = new TGeneric<MyClass>();
            Console.WriteLine("实例化类型为class的TGeneric的classTG成功");
        }
    }
}

运行结果:

4、泛型集合

泛型集合是可以将类型参数用作它所存储的对象的类型的点位符。

1、创建泛型集合

主要利用System.Collections.Generic命名空间下面的List<T>泛型类创建集合。

其语法格式如下:

List<T> list = new List<T>();

其中,尖括号就是一个泛型的标识,而T是一个类型的总称,也就是type,它既可以是简单类型,如string、int,也可以是用户自定义类型。list是泛型集合的名称。

编写程序,创建一个泛型集合,并为该集合添加元素。

using System;
using System.Collections.Generic;
namespace Project12
{
    class Person
    {
        private string _name; //姓名
        private int _score; //年龄
        //创建Person对象
        public Person(string Name, int Score)
        {
            this._name = Name;
            this._score = Score;
        }
        //姓名
        public string Name
        {
            get { return _name; }
        }
        //年龄
        public int Score
        {
            get { return _score; }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //创建Person对象
            Person p1 = new Person("张三", 90);
            Person p2 = new Person("李四", 80);
            Person p3 = new Person("王五", 70);
            //创建类型为Person的对象集合
            List<Person> list = new List<Person>();
            //将Person对象放入集合
            list.Add(p1);
            list.Add(p2);
            list.Add(p3);
            //输出第2个人的姓名和成绩
            Console.WriteLine(list[1].Name + "\t" + list[1].Score);
        }
    }
}

运行结果:

2、List类的作用

编程程序,将数组元素放入到List创建的泛型集合中,并调用各种方法对数组元素进行操作。

using System;
using System.Collections.Generic;  //泛型的英文名称Generic
using System.Collections;    //ArrayList
namespace Project13
{
    class Program
    {
        static void Main(string[] args)
        {
            //泛型结构的声明,和初始化的一个过程,list是泛型的名称
            List<int> list = new List<int>();
            //声明之后就于ArrayList添加元素一样
            list.Add(2);
            list.Add(4);
            int[] arrInt = { 1, 2, 3, 4, 5, 6 };
            list.AddRange(arrInt);    //添加一个数组
            Console.WriteLine("\n-------------遍历元素------------");
            for (int i = 0; i < list.Count; i++)
            {
                Console.Write(list[i] + "  ");
            }
            Console.WriteLine("\n-------------清除元素------------");
            list.Remove(2);
            for (int i = 0; i < list.Count; i++)
            {
                Console.Write(list[i] + "  ");
            }
            Console.WriteLine("\n-------------倒叙元素------------");
            list.Reverse();
            for (int i = 0; i < list.Count; i++)
            {
                Console.Write(list[i] + "  ");
            }
            Console.WriteLine("\n-------------排序元素------------");
            list.Sort();
            for (int i = 0; i < list.Count; i++)
            {
                Console.Write(list[i] + "  ");
            }
            Console.WriteLine();
        }
    }
}

运行结果:


-------------遍历元素------------
2  4  1  2  3  4  5  6
-------------清除元素------------
4  1  2  3  4  5  6
-------------倒叙元素------------
6  5  4  3  2  1  4
-------------排序元素------------
1  2  3  4  4  5  6

5、Dictionary类

在C#中,Dictionary提供快速的基于键值的元素查找。它的语法结构如下:

Dictionary<[key], [value]>

当用户有很多元素的时候可以使用它。它包含在System.Collections.Generic命名空间中。在使用前,必须声明它的键类型的值类型。

注意:

(1)从一组键到一组值的映射,每一个添加项都是由一个值及其相关联的键组成。

(2)任何键都必须是唯一的。

(3)键不能为空引用null,若值为引用类型,则可以为空值。

(4)Key和Value可以是任何类型(string, int, class等)。

1、Dictionary类的方法和属性

Dictionary类的属性
名称说明
Comparer获取用于确定字典中的键是否相等的IEqualityComparer<T>
Count获取包含在Dictionary <TKey, TValue>中的键/值对的数目
Item获取或设置与指定的键相关联的值
Keys获取包含Dictionary<TKey, TValue>中的键的集合
Values获取包含Dictionary<TKey, TValue>中的值的集合

Dictionary类的方法
名称说明
Add将指定的键和值添加到字典中
Clear从Dictionary<TKey, TValue>中移除所有的键和值
ContainsKey确定Dictionary<TKey, TValue>是否包含指定的键
ContainsValue确定Dictionary<TKey, TValue>是否包含指定值
GetEnumerator返回循环访问Dictionary<TKey, Tvalue>的枚举器
GetType获取当前实例的Type
Remove从Dictionary<TKey, Tvalue>中移除所指定的键的值
ToString返回表示当前对象的字符串
TyGetValue获取与指定的键相关联的值

2、Dictionary类的用法

编写程序,通过使用Dictionary类的键值对,对数据元素进行遍历、查找和移除的操作。

using System;
using System.Collections.Generic;
namespace Project14
{
    class Program
    {
        static void Main()
        {
            //实例化对象
            Dictionary<int, string> dc = new Dictionary<int, string>();
            //为集合添加元素
            dc.Add(1, "C#");
            dc.Add(2, "C++");
            dc.Add(3, "ASP.NET");
            dc.Add(4, "MVC");
            Console.WriteLine("-----KeyValuePair遍历元素-----");
            foreach (KeyValuePair<int, string> kvp in dc)
            {
                Console.WriteLine("Key = {0}; Value = {1}", kvp.Key, kvp.Value);
            }
            Console.WriteLine("--------通过Key查找元素-------");
            if (dc.ContainsKey(1))
            {
                Console.WriteLine("Key:{0},Value:{1}", "1", dc[1]);
            }
            Console.WriteLine("--------仅遍历键Keys属性------");
            Dictionary<int, string>.KeyCollection keyCol = dc.Keys;
            foreach (int key in keyCol)
            {
                Console.WriteLine("Key = {0}", key);
            }
            Console.WriteLine("-------仅遍历键Valus属性------");
            Dictionary<int, string>.ValueCollection valueCol = dc.Values;
            foreach (string value in valueCol)
            {
                Console.WriteLine("Value = {0}", value);
            }
            Console.WriteLine("-------Remove方法移除元素-----");
            dc.Remove(1);
            if (dc.ContainsKey(1))
            {
                Console.WriteLine("Key:{0},Value:{1}", "1", dc[1]);
            }
            else
            {
                Console.WriteLine("不存在 Key : 1");
            }
        }
    }
}

运行结果:

-----KeyValuePair遍历元素-----
Key = 1; Value = C#
Key = 2; Value = C++
Key = 3; Value = ASP.NET
Key = 4; Value = MVC
--------通过Key查找元素-------
Key:1,Value:C#
--------仅遍历键Keys属性------
Key = 1
Key = 2
Key = 3
Key = 4
-------仅遍历键Valus属性------
Value = C#
Value = C++
Value = ASP.NET
Value = MVC
-------Remove方法移除元素-----
不存在 Key : 1

四、泛型接口

为泛型集合类或表达集合中的项的泛型类定义接口通常很有用处。为避免对值类型的装箱或取消装箱操作,泛型类的首选项使用泛型接口。

在.NET Framework类库中定义了多个泛型接口,以将其用于System.Collections.Generic命名空间中的集合类。

1、泛型接口的声明

泛型接口的声明如下:

interface [接口名]<T>

{

        [接口体]

}

声明泛型接口时,与声明一般接口的区别是增加了一个“<T>”。一般来说,声明泛型接口与声明非泛型接口遵循相同规则 。

2、常用的泛型接口

(1)Collection<T>接口由集合类实现,继承于非泛型接口IEnumerable。通过Collection<T>可以把实现Collection<T>的对象传送给需要将IEnumerable对象作为参数的方法。

(2)List<T>接口和Collection<T>接口一样,也是继承于非泛型接口IEnumerable。List<T>接口允许使用索引符访问集合,用户还可以在集合的任意位置插入或删除集合中的元素。

(3)IEnumerable<T>接口支持在指定类型的集合上,进行简单迭代。它定义了GetEnumerator方法,返回一个实现IEnumerable<T>的枚举,如果对集合使用foreach语句,那么就需要用到这个接口。

(4)IEnumerators<T>接口,此接口继承了非泛型接口IEnumerators和IDisposable。该接口支持在指定类型的集合上进行简单迭代,foreach语句的使用实现了此接口的枚举访问集合中的所有元素。

(5)Dictionary<TKey, Tvalue>接口是由元素的一个键和一个值的集合实现的。

(6)Comparer<T>接口是为了比较两个对象而实现的方法,使用Compare方法给集合中的元素排序。

(7)IEqualityComparer<T>接口是比较对象的第二个接口,可以对对象进行相等比较。它的Equals方法用于比较两对象是否相等,如相等就返回true,否则返回false。它的GetHashCode方法为每个对象返回一个唯一的值。

五、泛型方法

在有些情况下,一个类型中可能只有少数的方法成员用到了类型参数,这时没有必要将整个类型都定义成为泛型类。因此,就引入 了泛型方法。

在C#的泛型机制中,只支持在方法声明上包含类型参数的方法称为泛型方法。泛型方法可以在泛型类型中使用,也可以在非泛型类型中使用。

泛型方法的声明格式如下:

[修饰符] void [方法名] <类型参数T>

{

        [方法体]

}

泛型方法与普通方法类似,只是在声明中包括类型参数T的方法。

注意:泛型方法定义的类型参数即可以作为方法的参数类型和返回类型,在foreach语句中也可以用来在方法的执行代码中定义局部变量。

编写程序,调用泛型方法。

using System;
namespace Project15
{
    //定义普通类
    public class MyClass
    {
        public bool Contains<T>(T[] TArry, T TValue)
        {
            foreach (T t in TArry)
            {
                //判断是否存在Tvalue
                if (t.Equals(TValue))
                {
                    return true;
                }           
            }
            return false;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //定义int类型的数组,并初始化
            int[] myint = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            //由于MyClass是一个非静态的类,所以需要进行实例化
            MyClass mc = new MyClass();
            //调用泛型方法
            bool mybool;
            int testInt = 20;
            //完整调用        
            mybool = mc.Contains<int>(myint, testInt);
            //简写调用
           // mybool = mc.Contains(myint, testInt);
            if(mybool)
                Console.WriteLine("数组中存在元素"+testInt);
            else
                Console.WriteLine("数组中不存在元素"+testInt);
        }
    }
}

C#集合与泛型 C#集合(ArrayList、List、SortedList、Hashtable、Dictionary、Stack、Queue、BitArray)与泛型类、泛型方法、泛型委托、约束泛型 阅读详情

相关推荐

【C#】C#结构体,枚举,泛型,事件,委托

一.结构体 二.特殊的结构体(ref struct): 三.枚举 四.泛型 泛型的使用: 1.泛型类:定义一个泛型类,使用类型参数T 2.泛型方法:在方法定义中使用类型参数 3.泛型接口 五.委托及泛型委托 委托 泛型委托 六.事件 事件: 泛型事件:使用泛型委托(如EventHandler)来声明事件,可以传递更具体的事件数据。 七.事件,委托,泛型结合使用

冰茶的博客 1475

Java学习【阶段一[06]】集合(03泛型)

一、泛型的概述 二、使用泛型的好处 创建集合对象,使用泛型 好处 1、避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型 2、把运行期异常(代码运行之后会抛出的异常),提升到了编译期异常(写代码的时候会报错 弊端 泛型是什么类型,只能存储什么类型的数据 创建集合对象,不使用泛型 好处: 集合不使用泛型,默认...

qq_41915980的博客 164

C#学习记录——数据结构(一)集合结构中的两种泛型集合

C#学习记录——数据结构 第一章 C#数据结构中集合结构中的两种泛型集合 文章目录C#学习记录——数据结构前言一、泛型集合(一)集合概述(二)数组基本使用步骤二、List和Dictionary 前言 数据结构是相互之间存在一种或多种特殊关系的数据元素的集合,如int、float等,本文主要介绍List和Dictionary<TKey, TValue>两个泛型集合。 一、泛型集合 (一)集合概述 集合:可以任意存储对象,并且长度是可变的类。 C#中集合结构有两种:泛型集合和非泛型集合。泛型集

weixin_42764899的博客 1003

# C#学习-泛型-集合-堆栈-队列-哈希-字典

C#学习第三周-泛型- 泛型 普通方法实现加法: 泛型方法实现加法: public static void Add<T>(T t1,T t2) { if(t1 is int) Console.WriteLine(int Parse(t1.tostring())+int.Parse(t2.ToString())); } if(t1 is float) { Console.WriteLine(float.Parse(t1.ToString())+float.Prase(t2.ToString()

努力前行,总会成为自己心中的那道光 1768

C# 集合与泛型

CSharp 集合与泛型的知识点

片言可决讼,半纸能缚龙 1795

C#泛型集合

轻松学会C#泛型集合,代码简洁清楚明了,让初学者一看就懂

C#里面的不同集合(数组、ArrayList集合、List泛型)

目录 数组(Array) 集合(ArrayList) 泛型(List) 那如何选择使用哪一个集合呢? 思维导图 数组(Array) 什么是数组? 是一个存储相同类型元素的固定大小的顺序集合。 有什么作用吗? 一次声明相同类型的数。 有哪些特点? 元素是相同类型 大小固定 元素连续存储 是引用类型(必须分配堆上的内存) 数组有哪些优点? 在内存中连续存储,因此可以快速而容易地从头到尾遍历元素,可以快速地修改元素 数组有哪些缺点呢? 创建时必须...

一起加油吧~ 3705

C#泛型集合与非泛型集合

在.NET FCL为我们提供了很多集合类型,是编程中非常有力的工具。泛型集合主要在 System.Collections.Generic名称空间中,而非泛型集合主要在System.Collections,首先抛出 结论:如果在C#2.0版本以上,尽量使用泛型集合类,而不使用非泛型集合类。因为,1. 泛型编程是从c#2.0开始才被.net支持的。2.泛型集合在性能和类型安全方面优于非泛型集 合。 。。。。

C#:List泛型集合

数组的不足 我们在使用数组管理数据的时候,是需要预先知道数组的长度的。但是在我们实际的开发过程中,很多数据往往无法事先知道一共有多少,在面对这些数据的时候,就无法使用数组来进行管理了。 一、集合结构 C#中提供了一系列特殊功能的类,这些类可以存储任意类型的对象,并且长度是可变的,他们统称为集合。 在 C#编程语言中,集合结构有两种:泛型集合,非泛型集合。 泛型集合:只能存储固定类型的对象...

信仰.的博客 1909

开源收银系统_大型收银系统源码_OctShop

开源收银系统正成为大型连锁企业数字化转型的关键工具。相比传统闭源系统,开源方案具有成本低(年均降本60%+)、定制灵活(支持多业态协同)、自主可控等优势,能有效解决高并发、多门店数据同步等痛点。核心价值在于:1)分布式架构适配规模化扩张;2)模块化设计实现个性化开发;3)开放接口打通ERP/CRM等系统。典型案例显示,连锁商超通过源码二次开发实现库存实时同步,补货效率提升50%;餐饮集团统一多业态收银流程后会员复购率增长35%。选型需关注源码成熟度、技术兼容性和安全合规,建议采用"开源+服务商&q

OctShop全栈工程师 938

浊音/清音/爆破音的时域及频域特性

第一周作业 浊音/清音/爆破音的时域及频域特性 思路:使用Audacity进行录制,时域部分将音频放大观察波形规律,频域部分生成并进行频谱分析。 (1)浊音U 时域分析: 时域表现为短周期性,波形比较规律。 频域分析: 频域上表现为频率集中在低频区域,共振峰较为明显,短时能量较高。 (2)清音S 时域分析: 时域波形没有周期性,整体振幅小于浊音。 频域分析: 频域波形平缓,无共振峰,能量比较集中。 (3)爆破音t 时域分析: 脉冲波,更为尖锐,整体上振幅降低。 频域分析: 没有像浊音一样的共振

Leylaaaa的博客 1228

C#之泛型

一、概述一、概述泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强大的类型检查,减少数据类型之间的显示转换、装箱操作和运行时的类型检查。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性,这是非泛型类和非泛型方法无法具备的。泛型通常用在集合和在集合上运行的方法中。泛型主要是提高了代码的重要性。

互联网底层民工的博客 2944

用Omniverse Kit开发第一个USD插件:从环境配置到实战案例(Python 3.7版)

本文详细介绍了如何使用NVIDIA Omniverse Kit和Python 3.7开发第一个USD插件,涵盖从环境配置到实战案例的全过程。通过创建可实时同步材质属性的USD插件,开发者可以快速掌握Omniverse开发框架,提升3D内容创作效率。

x8y9z0的博客 586

C#:泛型详解

本文详细介绍了C#中泛型的使用和理解

龟速船长 1085

Chapter 19 Digital Phase-Locked Loops

数字锁相环 Digital Phase-Locked Loops, 就是根据原来时钟信号, 产生新的时钟信号, which is locked or synchronized. (align 参考时钟边沿 or 在中间)

2304_76736886的博客 973

PaddleOCR训练自己的数据

一 、数据准备 采用PPOCRLabel标注自己的数据 PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置PP-OCR模型对数据自动标注和重新识别。使用Python3和PyQT5编写,支持矩形框标注和四点标注模式,导出格式可直接用于PaddleOCR检测和识别模型的训练。 1.1 安装PaddlePaddle pip3 install --upgrade pip # 如果您的机器安装的是CUDA9或CUDA10,请运行以下命令安装 python3 -m pip in.

zyb的博客 1万+

C#泛型精讲(泛型类、方法、接口、集合、default关键字、约束、动态类型)的用法(简单易懂)

本章节主要是介绍一些泛型用法,前三节是泛型类、方法、接口、集合的介绍,后三节是关于泛型中default关键字、泛型约束、动态类型的讲解。关于泛型委托会在下一节去讲,争取让大家在最短的时间内掌握好泛型,而不是一知半解。

qq_50812489的博客 2262

手把手教你学Simulink--基础储能管理场景实例:基于Simulink的锂电池健康状态(SOH)在线评估仿真

本文详细介绍了基于Simulink的锂电池健康状态(SOH)在线评估仿真方法。主要内容包括:1)SOH定义与量化指标(容量SOH、内阻SOH及综合SOH);2)基于Thevenin模型参数辨识和递推最小二乘法(RLS)的在线评估原理;3)100次充放电循环的仿真场景设置;4)Simulink建模步骤(主电路搭建、核心模块实现及信号流连接);5)仿真结果分析,显示SOH评估误差<2%,响应时间45秒,满足在线评估需求;6)提出多参数融合评估、深度学习辅助辨识等优化方向。该方法为储能系统寿命管理提供了有效

MHD0815的博客 181

C#中泛型<T>(特殊的占位符)的使用详解

泛型(Generic),是将不确定的类型预先定义下来的一种C#高级语法,我们在使用一个类,接口或者方法前,不知道用户将来传什么类型,或者我们写的类,接口或方法相同的代码可以服务不同的类型,就可以定义为泛型。这会大大简化我们的代码结构,同时让后期维护变得容易。泛型很适用于集合,我们常见的泛型集合有:List<T>,Dictionary<K,V>等等(T,K,V就代表不确定的类型,它是一种类型占位符),无一不是利用的泛型这一特性,若没有泛型,我们会多出很多重载方法,以解决类型不同,但是执行逻辑相同的情况。

u011555996的博客 3272

BurpSuite工具HaE插件好用正则收集

数据集合面板里面直接查询捕获到的相关数据内容,省去一个个翻找数据包内容的烦恼。插件捕获到匹配正则表达式的数据包后,可以在。可以对正则条目进行添加、编辑、删除。规则信息管理,我们点击。

墨痕诉清风的博客 648

AD22里面封装修改后,同步到PCB图里面

【摘要】本文介绍了Altium Designer 22中同步更新元件封装的三种方法:1)从PCB库直接更新:在PCB库面板右键选择"Update PCB With[封装名]";2)通过原理图标准更新:使用Design->Update PCB Document菜单;3)在PCB编辑器中验证更新:通过Tools->Update From PCB Libraries菜单。所有方法最终都需通过ECO(工程变更订单)确认变更,建议执行前仔细核对变更内容。这些方法适用于AD22及早期版本

whm128的博客 1761

C#中的泛型与非泛型--Generic

二、什么是泛型 如果你理解类是对象的模板(类是具有相同属性和行为的对象的抽象),那么泛型就很好理解了。 泛型:generic paradigm(通用的范式),generic这个单词也很好的说明了模板这个概念:通用的,标准的。泛型是类型的模板 不同的是:作为模板的类是通过实例化产生不同的对象,而泛型是通过不同的类型实参产生不同的类型 泛型的基本概念介绍完,我们来看看泛型到底是怎么帮我们解决问题的 ...

程序狗的成长之路 1025

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C# 泛型

泛型,泛型方法,泛型类,泛型约束,default,dynamic

鲤籽鲲的博客 1029

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C#泛型基础(一)之泛型介绍与泛型链表

一、泛型的优点 泛型是C#中相当重要的一部分,泛型有如下几个突出的有点: 1、性能。泛型的主要的一个优点就是性能,在实际项目中经常会遇到装箱和拆箱,尤其是在遍历的时候,频繁的装箱和拆箱会造成很大的性能损失,而泛型在泛型定义的时候就需要指定数据类型,在JIT编译器动态生成的类型中不再需要装箱和拆箱,如定义List<int> 2、类型安全。在泛型类中泛型类型T定义了允许使用的类型,如...

f363641380的博客 953

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C#编程篇 第04部分 C#简单集合与泛型集合

第04部分 C#简单集合与泛型集合 集合引用System.Collections 泛型集合引用System.Collections.Generic 1> 简单数据集合 1.1 ArrayList 动态数组ArrayList是C#封装好的类,本质是object的数组, ArrayList arr = new ArrayList(); <增>: arr.Add(object obj); arr.AddRange(Collections); <删>

weixin_52566131的博客 223
上一篇: 53. Maximum Subarray最大子数组和
下一篇: 69. Sqrt(x)x 的平方根
DXB2021
博客等级 码龄5年 307粉丝 289原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值