C# 用集合组织相关数据

作者: harde 分类: DotNet 发布时间: 2008-12-17 01:06

Harde原创于harde.org转载请注明
集合ArrayList和数组是十分相似的,事实上很多人称之为数组列表,
但是他们的区别也是很明显的,ArrayList可以非常直观地动态维护
比如说如果你定义了一个数组string [] test = new string[10];如果你想要再扩展容量,你只有使用Array.Resize(ref T[] array,int newSize);来扩张容量,而ArrayList就没有那么麻烦,因为它是动态的,因而在定义时既可以指定容量也可以不指定。
有一点要注意ArrayList是来自于System.Collections的,因此在使用前记得添加using System.Collections;。下面我来定义一个ArrayList
using System.Collections;
ArrayList Test = new ArrayList();
这就定义了一个ArrayList向ArrayList中添加元素很简单,只需要调用Add(Object value)即可
注意看这里是Object类型,因此当添加的元素为值类型的,会被转换为object引用类型后保存,所以ArrayList中所有的元素都是对象的引用。(Add()方法会返回一个int值,代表了刚才添加元素的索引)
请看示例

 private void btnMyClassTest_Click(object sender, EventArgs e)
        {
            //建立班级学员的集合
            ArrayList Students = new ArrayList();

            Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
            Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
            Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");

            Students.Add(scofield);
            Students.Add(zhang);
            Students.Add(jay);

            //打印集合数目
            MessageBox.Show(string.Format("共包括{0} 个学员。",
                Students.Count.ToString()));
        }


好了,会了添加让我们再来看下
存取单个元素
在数组中我们都是通过索引下标来访问元素的,ArrayList也不例外
但是有一点要注意
因为所有数据在ArrayList中都是以object类型存放的
因此再取的时候要转换成原来的数据类型
请看以下代码

         Student stu1 = (Student)Students[0];
            stu1.SayHi();

这段代码就会调用出scofield的学员资料
e697a0e6a087e9a298
好了,会了存取下面我们得看下删除了,删除ArrayList中的数据也很简单
使用

ArrayList.Remove(对象名) //删除指定对象名的对象
ArrayList.RemoveAt(index) //删除指定索引的对象
ArrayList.Clear() //清除集合内的所有元素

这三个方法就可以
比如Students.RemoveAt(0);就会删除scofield的资料,(同样我们也可以这样删除ArrayList.Remove(scofield))
说道数组,就不得不提下“遍历”
在日常使用中“遍历是我们经常用到的东西,通常对于数组,我们都是用for循环语句来遍历的,同样的ArrayList也不例外,另外ArrayList还可以使用foreach来遍历
代码:

            for (int i = 0; i < Students.Count; i++)
            {
                Student stuFor = (Student)Students&#91;i&#93;;
                Console.WriteLine(stuFor.Name);
            }
&#91;/csharp&#93;

再来看看用foreach遍历
&#91;csharp &#93;
    foreach (Object stuo in Students)
            {
                Student stuForeach = (Student)stuo;
                Console.WriteLine(stuForeach.Name);
            }
&#91;/csharp&#93;

这两种方法效果是一样的
但是有点区别,for是通过索引来访问元素,而foreach是通过对象来访问的。

常见错误
请问这样写对么?
&#91;csharp &#93;
Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");

students.Add(scofield);
students.Add(zhang);
students.Add(jay);

students.RemoveAt(0);
students.RemoveAt(1);
students.RemoveAt(2);

&#91;/csharp&#93;

答:错误,因为当第一次students.RemoveAt(0);后,数组中剩下2个元素,索引值为0、1,而下一行students.RemoveAt(1);则把索引值位1的元素删除了,而现在ArrayList中只剩下一个元素,下面紧接着又出现了students.RemoveAt(2);但是此时数组中只有一个元素,因此,此处会报错

(下面这个建议不讲~~)
请看下面一段代码,请问会输出什么?
&#91;csharp &#93;
public struct student
    {
        public student(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public string Name;
        public int Age;
    }
    class Program
    {
        static void Main(string&#91;&#93; args)
        {
            student stu1 = new student("张三",20);
            student stu2 = new student("李四", 20);
            student stu3 = new student("王五", 20);
            
            ArrayList students = new ArrayList();
            students.Add(stu1);
            students.Add(stu2);
            students.Add(stu3);

            foreach (student stu in students)
            {
                student myStudent = (student)stu;
                myStudent.Age = 60; //看这里看这里看这里
            }
            foreach (student stu in students)
            {
                Console.WriteLine(stu.Age);
            }
        }
}
&#91;/csharp&#93;

答案是不会,会输出20~
请问ArrayList中现在有几个元素
&#91;csharp &#93;Student stu2 = new Student("Scofield", Genders.Male, 28, "越狱狱");&#91;/csharp&#93;

//这条数据已经被添加到ArrayList中 ArrayList中目前有3个元素
我再定义一个stu2但是不添加到ArrayList中
&#91;csharp &#93;
Student stu2 = new Student("Scofield", Genders.Male, 28, "越狱狱");
Students.Remove(stu2);
&#91;/csharp&#93;

答案是不变,依旧为3个



HashTable


前面我们学习到了索引器来访问数组,很是方便,那我们能不能用类似索引器那种,通过关键字来获取对象呢?Yes it is!担不是ArrayList而是HashTable。
HashTable的数据是通过键和值来组织的(Key and Value)。
按我个人的理解可以参考ListView的ListViewItem与SubItem的关系
首先我们定义一个HashTable,HashTable和ArrayList一样都来自于是System.Collections的,因此不要忘了using System.Collections;
好了,我们来看下如何往HashTable中添加数值
&#91;csharp &#93;
         Hashtable Students = new Hashtable();

            Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
            Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
            Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");

            Students.Add(scofield.Name, scofield);
            Students.Add(zhang.Name, zhang);
            Students.Add(jay.Name, jay);
&#91;/csharp&#93;

怎么样很简单吧~,Ok,Go on
嗯,会添加那我们也得会取~
&#91;csharp &#93;Student stu2 = (Student)Students&#91;"周杰杰"&#93;;&#91;/csharp&#93;
怎么?太简单了?会了才叫简单~Understand?
依照惯例
下面就是遍历了,HashTable既然是Key----Value对应关系的,遍历时我们也多了一种选择
我们可以遍历Value
&#91;csharp &#93;
            foreach (Object stuo in Students.Values)
            {
                Student stu = (Student)stuo;
                Console.WriteLine(stu.Name);
            }
&#91;/csharp&#93;

同样也可以遍历Key
&#91;csharp &#93;
foreach (string name in students.Keys)
{
       Console.WriteLine(name); 
} 
&#91;/csharp&#93;

但是也同样是因为Key----Value对应关系,HashTable是不能通过索引来访问的。
现在会添会取会遍历,嗯?好像少点什么~呃~~删除
与ArrayList类似,HashTable的删除也是
            Students.Remove("周杰杰");
当然Remove()里面方的是key而不是Value,这一点一定要注意


泛型
首先看段代码((其实这里我也很头疼~~~)
&#91;csharp &#93;
         ArrayList Students = new ArrayList();

            Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
            Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
            Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");
            //创建一个老师对象
         Teacher jacky = new Teacher("成龙龙", 4);

            Students.Add(scofield);
            Students.Add(zhang);
            Students.Add(jay);
            //将老师对象添加到ArrayList
            Students.Add(jacky);
&#91;/csharp&#93;

添加是不会有问题的,但是当我们取的时候就会出现
<a href="http://harde.org/blog/wp-content/uploads/2008/12/e697a0e6a087e9a2981.jpg"><img src="http://harde.org/blog/wp-content/uploads/2008/12/e697a0e6a087e9a2981.jpg" alt="e697a0e6a087e9a2981" title="e697a0e6a087e9a2981" width="406" height="260" class="alignnone size-full wp-image-789" /></a>
从代码来看很明显,我们把Teacher对象添加到了学生的集合里,当取的时候进行类型转换时就会出错
怎么办呢?那就得请出本节课的BOSS,泛型与泛型集合
泛型:泛型是C#2.0中的一个新特性。通过泛型可以定义类型安全的数据类型,它的最显著应用就是创建集合类,可以约束集合类内的元素类型,比较典型的就是List<T>,Dictionary<K,V>(<T>、<K,V>表示该泛型集合中的元素类型)
泛型集合List<T>使用的是System.Collections.Generic命名空间,这点有别于ArrayList与HashTable。
List<T>的使用非常类似与ArrayList,只不过相当于了ArrayList List<T>有更好的安全性
我们首先定义一个List<T>
[csharp ]List<Student> students = new List<Student>();

我们再次尝试一下开头的代码

         Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
            Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
            Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");
            Teacher jacky = new Teacher("成龙龙", 4);
            students.Add(scofield);
            students.Add(zhang);
            students.Add(jay);

看,在编译时立即就出错了
e697a0e6a087e9a2982
对于 List的操作,大家可以参照ArrayList,在此我就不再赘述。
在遍历时有点区别,就是List不需要类型转换~,为了方面大家对比两者关系,我画了张表
e697a0e6a087e9a2983
下面我们看下 泛型集合Dictionary
刚才说过了List与ArrayList相类似
同样的Dictionary也类似于HashTable,
我们先来定义一个Dictionary

            Dictionary<String, Student> students = new Dictionary<string, Student>();

            Student scofield = new Student("Scofield", Genders.Male, 28, "越狱狱");
            Student zhang = new Student("张靓靓", Genders.Female, 20, "唱歌歌");
            Student jay = new Student("周杰杰", Genders.Male, 21, "耍双节棍棍");

添加数据

         students.Add(scofield.Name, scofield);
            students.Add(zhang.Name, zhang);
            students.Add(jay.Name, jay);

完全和HashTable是一样的

最后我们来看下HashTable与Dictionary的对比
e697a0e6a087e9a2984

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注