C#集合、定义集合、索引符、List<T>、Dictionary<K,V>、键控集合(键值)和IDictionary

发布于:2022-12-03 ⋅ 阅读:(675) ⋅ 点赞:(0)

目录

一、集合

二、使用集合

三、定义集合

四、索引符

五、使用List泛型集合类

六、键控集合和IDictionary

七、使用Dictionary<K,V>泛型集合类


一、集合

集合类Collection Class

C#中的数组实现为System.Array类的实例,只是集合类中的一种类型

集合类一般用于处理对象列表,功能大多是通过实现System.Collections名称空间中的接口而获得

集合的功能(包括基本功能)可以通过接口来实现,可以使用基本集合类(System.Array),可以创建定制集合类

System.Collections名称空间中的几个接口提供了基本的集合功能:

IEnumerable可以迭代集合中的项

ICollection(继承于IEnumerable)可以获取集合中项的个数,并能把项复制到一个简单的数组类型中

IList(继承于IEnumerable和ICollection)提供了集合的项列表,允许访问这些项,并提供其他一些与项列表相关的基本功能

IDictionary(继承于IEnumerable和ICollection)类似于IList,但提供了可通过键值(而不是索引)访问的项列表

System.Array类实现了IList、ICollection和IEnumerable,但不支持IList的一些更高级功能,它表示大小固定的项列表

二、使用集合

Systems.Collections名称空间中的类System.Collections.ArrayList也实现了IList、ICollection和IEnumerable接口,但实现方式比System.Array更复杂。

System.Array数组的大小是固定不变的(不能添加或删除元素)

System.Collections.ArrayList类可以用于表示大小可变的项列表

代码参考:

https://media.wiley.com/product_ancillary/85/11190966/DOWNLOAD/Chapter11code.zip

准备好的基类和派生类先写在这里,使用的命名空间都是Animals

基类 Animal.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{   
    /// <summary>
    /// 
    /// </summary>
    public abstract class Animal
    {
        protected string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public Animal()
        {
            name = "The animal with no name";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed() => WriteLine($"{name} has been fed.");
    }
}

派生类 Cow.cs  Chicken.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{
    public class Cow : Animal
    {
        public void Milk() => WriteLine($"{name} has been milked.");

        public Cow(string newName) : base(newName) { }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{
    public class Chicken : Animal
    {
        public void LayEgg() => WriteLine($"{name} has laid an egg.");

        public Chicken(string newName) : base(newName) { }
    }
}

第一个集合使用System.Array类(这是一个简单数组),Animal对象

//Animal类是抽象类,不能实例化,但通过多态性,使集合中的项成为派生于Animal类的Cow和Chicken类实例

//对于简单数组,用固定的大小来初始化数组
         Animal[] animalArray = new Animal[2];

//数组是引用类型(如Animal和Animal派生的对象),用长度初始化数据,但并没有初始化它包含的项;
//要使用一个指定的项还需初始化,赋予初始化完成的对象

//用现有的Cow对象来赋值,或者通过创建一个新的Chicken对象来赋值
	         Cow myCow1 = new Cow("Lea");
         animalArray[0] = myCow1;
         animalArray[1] = new Chicken("Noa");
//Systen.Array类实现IEnumerable接口,这个接口的唯一方法GetEnumerator()可以迭代集合中的各项
         foreach (Animal myAnimal in animalArray)
         {
            WriteLine($"New {myAnimal.ToString()} object " 
             + $"added to Array collection, Name = {myAnimal.Name}");
         }
//使用数组的Length属性,输出数组中元素的个数
        WriteLine($"Array collection contains {animalArray.Length} objects.");
//简单数组是强类型化的,可以直接访问所包含的项类型,直接调用项的方法
         animalArray[0].Feed();
//数组的类型时抽象类型Animal,不能直接调用由派生类提供的方法,而必须使用数据类型转换
         ((Chicken)animalArray[1]).LayEgg();
         WriteLine();

         WriteLine("Create an ArrayList type collection of Animal " +
                       "objects and use it:");

第二个集合使用System.Collections.ArrayList类,Animal对象

//Animal类是抽象类,不能实例化,但通过多态性,使集合中的项成为派生于Animal类的Cow和Chicken类实例
//ArrayList集合不需要初始化其大小,创建animalArrayList列表:这个类还有另外两种构造函数,
//1、构造函数把现有的集合作为一个参数,将其内容复制到新实例中;
//2、而另一个构造函数通过一个参数设置集合的容量(capacity)。
//这个容量用一个int值指定,设置集合中可以包含的初始项数。但这并不是绝对容量,因为若集合中的项数超过该值,容量会自动增加一倍
         ArrayList animalArrayList = new ArrayList();
//对于ArrayList集合,没有现成的项,也没有null引用的项。
//使用ArrayList对象的Add()方法添加新项
         Cow myCow2 = new Cow("Rual");
         animalArrayList.Add(myCow2);
         animalArrayList.Add(new Chicken("Andrea"));
//ArrayList对象也支持IEnumerable接口,可以与foreach一起使用
         foreach (Animal myAnimal in animalArrayList)
         {
            WriteLine($"New {myAnimal.ToString()} object added to ArrayList collection," + 
                 $"Name = {myAnimal.Name}");
         }
//使用Count属性,输出ArrayList对象中元素的个数,该属性是ICollection接口的一部分
         WriteLine($"ArrayList collection contains {animalArrayList.Count} objects.");
//ArrayList集合是System.Object对象的集合(通过多态性赋给Animal对象),所以必须对所有的项进行数据类型转换
         ((Animal)animalArrayList[0]).Feed();
         ((Chicken)animalArrayList[1]).LayEgg();
         WriteLine();
         WriteLine("Additional manipulation of ArrayList:");
//利用的一些ArrayList集合功能超出了Array集合的功能范围
//可以使用Remove()和RemoveAt()方法删除项,这两个方法是在ArrayList类中实现的IList接口的一部分,
//他们分别根据项的引用或索引从数组中删除项

//删除列表中的第一项,即Name属性为Rual的Cow对象
//也可以使用animalArrayList.Add(myCow2);效果相同
         animalArrayList.RemoveAt(0);
//集合中剩余的项是Chicken对象
//当对ArrayList对象中的项进行修改,使数组中剩下N个项时,其索引范围变为0~N-1,
//例如:删除索引为0的项,会使其他项在数组中移动一个位置,所以应使用索引0(而非1)来访问Chicken对象。
//不再有索引为1的项了(因为集合中最初只有两个项),所以使用((Animal)animalArrayList[1]).Feed();,就会抛出异常
         ((Animal)animalArrayList[0]).Feed();
//ArrayList集合可用AddRange()方法一次添加多项,该方法接受带ICollection接口的任意对象,包括前面代码创建的animalArray数组

//AddRange()方法不是ArrayList提供的任何接口的一部分,这个方法专用于ArrayList类
//还可以使用InsertRange(),可以把数组对象插入到列表中的任何位置
         animalArrayList.AddRange(animalArray);
         ((Chicken)animalArrayList[2]).LayEgg();
//使用IList接口中的IndexOf()方法可以看出myCow1(最初添加到animalArray中的一个对象)
//现在是animalArrayList集合的一部分
         Console.WriteLine($"The animal called {myCow1.Name} is at " +
             $"index {animalArrayList.IndexOf(myCow1)}.");
//通过对象引用重新命名了对象
         myCow1.Name = "Mary";
         WriteLine("The animal is now " +
              $"called {((Animal)animalArrayList[1]).Name}.");
         ReadKey();

三、定义集合

创建自己的强类型化的集合

从一个类中派生出自己的集合,例如System.Collections.CollectionBase类,这个抽象类提供大量实现代码

CollectionBase类有接口IEnumerable、ICollection和IList,主要是IList的Clear()和RemoveAt()方法,以及ICollection的Count属性

CollectionBase提供了两个受保护的属性,它们可以访问存储的对象本身,可以使用List和InnerList,List可以通过IList接口访问项,InnerList则是用于存储项的ArrayList对象

存储Animal对象的集合类

代码中的Add()和Remove()方法实现为强类型化的方法,使用IList接口中用于访问项的标准Add()方法。这些方法现在只用于处理Animal类或派生于Animal的类,而前面介绍的ArrayList实现代码可以处理任何对象

public class Animals:CollectionBase
{
    public void Add(Animal newAnimal)
    {
        List.Add(newAnimal);
    }

    public void Remove(Animal oldAnimal)
    {
        List.Remove(oldAnimal);
    }

    public Animals()
    {
    }
}

CollectionBase类可以对派生的集合使用foreach语法

Console.WriteLine("Using custom collection class Animals:");
Animals animalCollection = new Animals();
animalCollection.Add(new Cow("Sarah"));
foreach(Animal myAnimal in animalCollection)
{
    Console.WriteLine("New {0} object added to custom collection, " +
                      "Name = {1}", myAnimal.ToString(), myAnimal.Name);
}

但不能使用以下的代码:

animalCollection[0].Feed();

若要以这种方式,需通过索引来访问项,就需要使用索引符

四、索引符

索引符(indexer)是一种特殊类型的属性,可以添加到一个类中,以提供类似于数组的访问

常见用法是对项实现简单的数字索引

//在Animal对象的Animals集合中添加一个索引符
//this关键字需要与方括号中的参数一起使用
public class Animals:CollectionBase
{
    ...
    public Animals this[int animalIndex]
    {
        get
        {
            //这段代码对List属性使用一个索引符(即在IList接口上,
            //可以访问CollectionBase中的ArrayList,ArrayList存储了项)
            return (Animal)List[animalIndex];
        }
        set
        {
            //需要显式数据类型转换,因为IList.List属性返回一个System.Object对象
            List[animalIndex] = value;
        }
    }
}

这种强类型化功能意味着可使用代码:

animalCollection[0].Feed();

而不是

((Animal)animalCollection[0]).Feed();

代码参考:

https://media.wiley.com/product_ancillary/85/11190966/DOWNLOAD/Chapter11code.zip

修改 Program.cs的程序

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{
    class Program
    {
        static void Main(string[] args)
        {
            //集合使用自己创建的强类型化的集合
            AnimalList animalList = new AnimalList();
            Cow myCow2 = new Cow("Rual");
            animalList.Add(myCow2);
            animalList.Add(new Chicken("Andrea"));

            foreach (Animal myAnimal in animalList)
            {
                WriteLine($"New {myAnimal.ToString()} object added to ArrayList collection," +
                             $" Name = {myAnimal.Name}");
            }
            WriteLine($"ArrayList collection contains {animalList.Count} "
                + " objects.");

            animalList[0].Feed();
            ((Chicken)animalList[1]).LayEgg();
            WriteLine();
        }
    }
}

五、使用List<T>泛型集合类

List<T>泛型集合类更加快捷和易于使用,不必和从CollectionBase中派生一个类(前文的方法)

使用List<T>泛型集合类进行替换上述自己的强类型化的集合Animals,可删除Animals.cs文件,无需声明Animals类

使用命名空间System.Collections.Generic

Programm.cs修改为

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{
    class Program
    {
        static void Main(string[] args)
        {
            //使用System.Collections.Generic命名空间中的泛型集合类
            List<Animal> animalList = new List<Animal>();
            Cow myCow2 = new Cow("Rual");
            animalList.Add(myCow2);
            animalList.Add(new Chicken("Andrea"));

            foreach (Animal myAnimal in animalList)
            {
                WriteLine($"New {myAnimal.ToString()} object added to ArrayList collection," +
                             $" Name = {myAnimal.Name}");
            }
            WriteLine($"ArrayList collection contains {animalList.Count} "
                + " objects.");

            animalList[0].Feed();
            ((Chicken)animalList[1]).LayEgg();
            WriteLine();
        }
    }
}

  

六、键控集合和IDictionary

除了IList接口外,集合还可以实现类似IDictionary接口,允许项通过键值(如字符串名)进行索引,而不是通过一个索引。可使用索引符完成,但这次的索引符参数是与存储的项相关联的键,而不是int索引

使用DictionaryBase基类简化IDictionary接口的实现,基类实现IEnumerable和ICollection,提供对任何集合都相同的基本集合处理功能

DictionaryBase与CollectionBase一样,实现通过其支持的接口获得的一些成员(但不是全部成员)。DictionaryBase也实现Clear和Count成员,但不实现RemoveAt()。

RemoveAt()是IList接口中的一个方法,不是IDictionary接口中的一个方法。

IDictionary有一个Remove()方法,这是基于DictionaryBase的定制集合类上实现的方法。

Animals类的另一个版本,该类派生于DictionaryBase,包括Add()、Remove()和一个通过键访问的索引符的实现代码:

public class Animals:DictionaryBase
{
    //Add()带有两个参数:一个键和一个值,存储在一起
    //字典集合有一个继承于DictionaryBase的成员Dictionary,这个成员是一个IDictionary接口,
    //有自己的Add()方法,该方法带有两个object参数

    //实现代码使用一个string值作为键,使用一个Animal对象作为与该键存储在一起的数据
    public void Add(string newID, Animal newAnimal)
    {
        Dictionary.Add(newID, newAnimal);
    }

    //以一个键而不是对象引用作为参数,与指定键值对应的项被删除
    public void Remove(string animalID)
    {
        Dictionary.Remove(animalID);
    }

    public Animals()
    {
    
    }

    //使用一个字符串键值,而不是一个索引,用于通过Dictionary的继承成员来访问存储的项,仍需数据类型转换
    public Animal this[string animalID]
    {
        get
        {
            return (Animal)Dictionary[animalID];
        }
        set
        {
            Dictionary[animalID] = value;
        }
    }
}

七、使用Dictionary<K,V>泛型集合类

这个类型可以定义键/值对的集合,该类需要实例化两个类型,分别用于键和值,以表达集合中的各个项
使用该类和List<T>使用情况大致相同,无需再声明Animals类,索引符可使用string类或枚举

使用命名空间System.Collections.Generic

Programm.cs修改为

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Animals
{
    class Program
    {
        static void Main(string[] args)
        {
            //使用System.Collections.Generic命名空间中的泛型集合类
            //使用Dictionary<K,V>泛型集合类
            Dictionary<string,Animal> animalDict = new Dictionary<string,Animal>();
            Cow myCow2 = new Cow("Rual");
            animalDict.Add("Cow",myCow2);
            animalDict.Add("Chicken",new Chicken("Andrea"));

            foreach (string key in animalDict.Keys)
            {
                WriteLine(key);
            }
            foreach (Animal value in animalDict.Values)
            {
                WriteLine(value.Name);
            }

            animalDict["Cow"].Feed();
            ((Chicken)animalDict["Chicken"]).LayEgg();
            WriteLine();
        }
    }
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到